{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T10:43:59.692151Z",
     "start_time": "2025-01-24T10:43:35.760802Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-24T10:47:50.943525Z",
     "iopub.status.busy": "2025-01-24T10:47:50.943366Z",
     "iopub.status.idle": "2025-01-24T10:47:54.636965Z",
     "shell.execute_reply": "2025-01-24T10:47:54.636442Z",
     "shell.execute_reply.started": "2025-01-24T10:47:50.943505Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
      "  from .autonotebook import tqdm as notebook_tqdm\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sys.version_info(major=3, minor=10, micro=14, releaselevel='final', serial=0)\n",
      "matplotlib 3.10.0\n",
      "numpy 1.26.4\n",
      "pandas 2.2.3\n",
      "sklearn 1.6.0\n",
      "torch 2.5.1+cu124\n",
      "cuda:0\n"
     ]
    }
   ],
   "source": [
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "from tqdm.auto import tqdm\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "print(sys.version_info)\n",
    "for module in mpl, np, pd, sklearn, torch:\n",
    "    print(module.__name__, module.__version__)\n",
    "    \n",
    "device = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
    "print(device)\n",
    "\n",
    "seed = 42\n",
    "torch.manual_seed(seed)\n",
    "torch.cuda.manual_seed_all(seed)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-24T10:47:54.638531Z",
     "iopub.status.busy": "2025-01-24T10:47:54.638079Z",
     "iopub.status.idle": "2025-01-24T10:47:59.439293Z",
     "shell.execute_reply": "2025-01-24T10:47:59.438638Z",
     "shell.execute_reply.started": "2025-01-24T10:47:54.638502Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Looking in indexes: https://mirrors.cloud.aliyuncs.com/pypi/simple\n",
      "Requirement already satisfied: tensorflow in /usr/local/lib/python3.10/site-packages (2.18.0)\n",
      "Requirement already satisfied: absl-py>=1.0.0 in /usr/local/lib/python3.10/site-packages (from tensorflow) (2.1.0)\n",
      "Requirement already satisfied: astunparse>=1.6.0 in /usr/local/lib/python3.10/site-packages (from tensorflow) (1.6.3)\n",
      "Requirement already satisfied: flatbuffers>=24.3.25 in /usr/local/lib/python3.10/site-packages (from tensorflow) (25.1.21)\n",
      "Requirement already satisfied: gast!=0.5.0,!=0.5.1,!=0.5.2,>=0.2.1 in /usr/local/lib/python3.10/site-packages (from tensorflow) (0.6.0)\n",
      "Requirement already satisfied: google-pasta>=0.1.1 in /usr/local/lib/python3.10/site-packages (from tensorflow) (0.2.0)\n",
      "Requirement already satisfied: libclang>=13.0.0 in /usr/local/lib/python3.10/site-packages (from tensorflow) (18.1.1)\n",
      "Requirement already satisfied: opt-einsum>=2.3.2 in /usr/local/lib/python3.10/site-packages (from tensorflow) (3.4.0)\n",
      "Requirement already satisfied: packaging in /usr/local/lib/python3.10/site-packages (from tensorflow) (24.2)\n",
      "Requirement already satisfied: protobuf!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<6.0.0dev,>=3.20.3 in /usr/local/lib/python3.10/site-packages (from tensorflow) (5.29.2)\n",
      "Requirement already satisfied: requests<3,>=2.21.0 in /usr/local/lib/python3.10/site-packages (from tensorflow) (2.32.3)\n",
      "Requirement already satisfied: setuptools in /usr/local/lib/python3.10/site-packages (from tensorflow) (69.5.1)\n",
      "Requirement already satisfied: six>=1.12.0 in /usr/local/lib/python3.10/site-packages (from tensorflow) (1.17.0)\n",
      "Requirement already satisfied: termcolor>=1.1.0 in /usr/local/lib/python3.10/site-packages (from tensorflow) (2.5.0)\n",
      "Requirement already satisfied: typing-extensions>=3.6.6 in /usr/local/lib/python3.10/site-packages (from tensorflow) (4.12.2)\n",
      "Requirement already satisfied: wrapt>=1.11.0 in /usr/local/lib/python3.10/site-packages (from tensorflow) (1.17.0)\n",
      "Requirement already satisfied: grpcio<2.0,>=1.24.3 in /usr/local/lib/python3.10/site-packages (from tensorflow) (1.69.0)\n",
      "Requirement already satisfied: tensorboard<2.19,>=2.18 in /usr/local/lib/python3.10/site-packages (from tensorflow) (2.18.0)\n",
      "Requirement already satisfied: keras>=3.5.0 in /usr/local/lib/python3.10/site-packages (from tensorflow) (3.8.0)\n",
      "Requirement already satisfied: numpy<2.1.0,>=1.26.0 in /usr/local/lib/python3.10/site-packages (from tensorflow) (1.26.4)\n",
      "Requirement already satisfied: h5py>=3.11.0 in /usr/local/lib/python3.10/site-packages (from tensorflow) (3.12.1)\n",
      "Requirement already satisfied: ml-dtypes<0.5.0,>=0.4.0 in /usr/local/lib/python3.10/site-packages (from tensorflow) (0.4.1)\n",
      "Requirement already satisfied: tensorflow-io-gcs-filesystem>=0.23.1 in /usr/local/lib/python3.10/site-packages (from tensorflow) (0.37.1)\n",
      "Requirement already satisfied: wheel<1.0,>=0.23.0 in /usr/local/lib/python3.10/site-packages (from astunparse>=1.6.0->tensorflow) (0.44.0)\n",
      "Requirement already satisfied: rich in /usr/local/lib/python3.10/site-packages (from keras>=3.5.0->tensorflow) (13.9.4)\n",
      "Requirement already satisfied: namex in /usr/local/lib/python3.10/site-packages (from keras>=3.5.0->tensorflow) (0.0.8)\n",
      "Requirement already satisfied: optree in /usr/local/lib/python3.10/site-packages (from keras>=3.5.0->tensorflow) (0.14.0)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/site-packages (from requests<3,>=2.21.0->tensorflow) (3.4.1)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/site-packages (from requests<3,>=2.21.0->tensorflow) (3.10)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/site-packages (from requests<3,>=2.21.0->tensorflow) (2.3.0)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/site-packages (from requests<3,>=2.21.0->tensorflow) (2024.12.14)\n",
      "Requirement already satisfied: markdown>=2.6.8 in /usr/local/lib/python3.10/site-packages (from tensorboard<2.19,>=2.18->tensorflow) (3.7)\n",
      "Requirement already satisfied: tensorboard-data-server<0.8.0,>=0.7.0 in /usr/local/lib/python3.10/site-packages (from tensorboard<2.19,>=2.18->tensorflow) (0.7.2)\n",
      "Requirement already satisfied: werkzeug>=1.0.1 in /usr/local/lib/python3.10/site-packages (from tensorboard<2.19,>=2.18->tensorflow) (3.1.3)\n",
      "Requirement already satisfied: MarkupSafe>=2.1.1 in /usr/local/lib/python3.10/site-packages (from werkzeug>=1.0.1->tensorboard<2.19,>=2.18->tensorflow) (2.1.5)\n",
      "Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.10/site-packages (from rich->keras>=3.5.0->tensorflow) (3.0.0)\n",
      "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.10/site-packages (from rich->keras>=3.5.0->tensorflow) (2.19.0)\n",
      "Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.10/site-packages (from markdown-it-py>=2.2.0->rich->keras>=3.5.0->tensorflow) (0.1.2)\n",
      "\u001B[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001B[0m\u001B[33m\n",
      "\u001B[0m\n",
      "\u001B[1m[\u001B[0m\u001B[34;49mnotice\u001B[0m\u001B[1;39;49m]\u001B[0m\u001B[39;49m A new release of pip is available: \u001B[0m\u001B[31;49m23.3.2\u001B[0m\u001B[39;49m -> \u001B[0m\u001B[32;49m24.3.1\u001B[0m\n",
      "\u001B[1m[\u001B[0m\u001B[34;49mnotice\u001B[0m\u001B[1;39;49m]\u001B[0m\u001B[39;49m To update, run: \u001B[0m\u001B[32;49mpip install --upgrade pip\u001B[0m\n"
     ]
    }
   ],
   "source": [
    "!pip install tensorflow"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 准备数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T10:44:31.609275Z",
     "start_time": "2025-01-24T10:43:59.693152Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-24T10:47:59.440320Z",
     "iopub.status.busy": "2025-01-24T10:47:59.440012Z",
     "iopub.status.idle": "2025-01-24T10:48:04.395739Z",
     "shell.execute_reply": "2025-01-24T10:48:04.395182Z",
     "shell.execute_reply.started": "2025-01-24T10:47:59.440298Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-01-24 18:47:59.590871: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.\n",
      "2025-01-24 18:47:59.602795: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:477] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n",
      "WARNING: All log messages before absl::InitializeLog() is called are written to STDERR\n",
      "E0000 00:00:1737715679.617510     538 cuda_dnn.cc:8310] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n",
      "E0000 00:00:1737715679.621976     538 cuda_blas.cc:1418] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n",
      "2025-01-24 18:47:59.636786: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n",
      "To enable the following instructions: AVX2 AVX512F AVX512_VNNI FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n"
     ]
    }
   ],
   "source": [
    "from tensorflow import keras\n",
    "#用karas有的数据集imdb，电影分类,分电影是积极的，还是消极的\n",
    "imdb = keras.datasets.imdb\n",
    "#载入数据使用下面两个参数\n",
    "vocab_size = 10000  #词典大小，仅保留训练数据中前10000个最经常出现的单词，低频单词被舍弃\n",
    "index_from = 3  #0,1,2,3空出来做别的事\n",
    "#前一万个词出现词频最高的会保留下来进行处理，后面的作为特殊字符处理，\n",
    "# 小于3的id都是特殊字符，下面代码有写\n",
    "# 需要注意的一点是取出来的词表还是从1开始的，需要做处理\n",
    "(train_data, train_labels), (test_data, test_labels) = imdb.load_data(\n",
    "    num_words = vocab_size, index_from = index_from)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T10:44:31.614323Z",
     "start_time": "2025-01-24T10:44:31.610276Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-24T10:48:04.397357Z",
     "iopub.status.busy": "2025-01-24T10:48:04.396756Z",
     "iopub.status.idle": "2025-01-24T10:48:04.400440Z",
     "shell.execute_reply": "2025-01-24T10:48:04.399919Z",
     "shell.execute_reply.started": "2025-01-24T10:48:04.397334Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train 25000 (25000,)\n",
      "test 25000 (25000,)\n"
     ]
    }
   ],
   "source": [
    "\n",
    "print(\"train\", len(train_data), train_labels.shape)  #25000个样本，每个样本是一段话，每个单词用一个数字表示\n",
    "print(\"test\", len(test_data), test_labels.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T10:44:31.678022Z",
     "start_time": "2025-01-24T10:44:31.614323Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-24T10:48:04.401258Z",
     "iopub.status.busy": "2025-01-24T10:48:04.400967Z",
     "iopub.status.idle": "2025-01-24T10:48:04.443508Z",
     "shell.execute_reply": "2025-01-24T10:48:04.443030Z",
     "shell.execute_reply.started": "2025-01-24T10:48:04.401229Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "88584\n",
      "<class 'dict'>\n"
     ]
    }
   ],
   "source": [
    "#载入词表，看下词表长度，词表就像英语字典\n",
    "word_index = imdb.get_word_index()\n",
    "print(len(word_index))\n",
    "print(type(word_index))\n",
    "#词表虽然有8万多，但是我们只载入了最高频的1万词！！！！"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 构造 word2idx 和 idx2word"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T10:44:31.726321Z",
     "start_time": "2025-01-24T10:44:31.680020Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-24T10:48:04.444219Z",
     "iopub.status.busy": "2025-01-24T10:48:04.444047Z",
     "iopub.status.idle": "2025-01-24T10:48:04.473201Z",
     "shell.execute_reply": "2025-01-24T10:48:04.472711Z",
     "shell.execute_reply.started": "2025-01-24T10:48:04.444200Z"
    }
   },
   "outputs": [],
   "source": [
    "word2idx = {word: idx + 3 for word, idx in word_index.items()}\n",
    "word2idx.update({\n",
    "    \"[PAD]\": 0,     # 填充 token\n",
    "    \"[BOS]\": 1,     # begin of sentence\n",
    "    \"[UNK]\": 2,     # 未知 token\n",
    "    \"[EOS]\": 3,     # end of sentence\n",
    "})\n",
    "\n",
    "idx2word = {idx: word for word, idx in word2idx.items()}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T10:44:33.240433Z",
     "start_time": "2025-01-24T10:44:31.727321Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-24T10:48:04.475436Z",
     "iopub.status.busy": "2025-01-24T10:48:04.475035Z",
     "iopub.status.idle": "2025-01-24T10:48:05.482750Z",
     "shell.execute_reply": "2025-01-24T10:48:05.482190Z",
     "shell.execute_reply.started": "2025-01-24T10:48:04.475414Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAigAAAGdCAYAAAA44ojeAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAO+RJREFUeJzt3Xl4FFW+//FPb4mJZjGBbGPYlUUCAmqIC8IlCnFFcAYUHVAGRAMjoIjxqqDee8Oo4zKKOI4Kziji6GVxcMSHHZeAgCAgiIAoqAkwMiQskvRyfn94qZ8t6UCgU90N79fz1OPpqtPV3zq0qW+fU3XKYYwxAgAAiCLOSAcAAADwSyQoAAAg6pCgAACAqEOCAgAAog4JCgAAiDokKAAAIOqQoAAAgKhDggIAAKKOO9IBHI9AIKDvv/9eSUlJcjgckQ4HAAAcA2OM9u3bp5ycHDmddfeRxGSC8v333ys3NzfSYQAAgOOwY8cOnXXWWXXWickEJSkpSdJPB5icnBzhaAAAwLGoqqpSbm6udR6vS0wmKIeHdZKTk0lQYojf79eyZcskSV27dpXL5YpwRACASDiWyzNiMkFBbPL7/Zo/f74k6YILLiBBAQCERIIC2zidTnXs2NEqAwAQCgkKbON2u9WnT59IhwEAiAH1SlBKS0s1Y8YMffHFF0pISNBFF12kP/zhD2rdurVV59ChQ7r77rs1ffp0VVdXq1evXnr++eeVmZlp1dm+fbvuuOMOLVq0SGeccYYGDRqk0tJSud3kSwBwMjDGyOfzye/3RzoU2MjlcsntdodlCpB6ZQRLlixRcXGxLrjgAvl8Pt1///264oortGHDBp1++umSpNGjR+vdd9/VW2+9pZSUFI0YMUJ9+/bVRx99JOmn6xCuuuoqZWVl6eOPP1Z5ebl++9vfyuPx6H/+539O+IAAAJFVU1Oj8vJyHTx4MNKhIAISExOVnZ2tuLi4E9qPwxhjjvfNu3fvVkZGhpYsWaJu3bqpsrJSjRs31rRp03TDDTdIkr744gu1bdtWZWVl6tq1q9577z1dffXV+v77761elRdeeEHjxo3T7t27j+mAqqqqlJKSosrKSu7iiSE1NTV68sknJUljxow54S8vgOgTCAS0efNmuVwuNW7cWHFxcUyoeYowxqimpka7d++W3+/X2WeffcT1hvU5f5/QmEplZaUkKS0tTZK0atUqeb1eFRYWWnXatGmjJk2aWAlKWVmZ8vLygoZ8evXqpTvuuEOff/65OnXqdMTnVFdXq7q6OugAEZt+/u8I4ORTU1OjQCCg3NxcJSYmRjoc2CwhIUEej0fffPONampqdNpppx33vo47QQkEAho1apQuvvhitW/fXpJUUVGhuLg4paamBtXNzMxURUWFVefnycnh7Ye31aa0tFQPP/zw8YaKKOHxeDRixAirDODkxZ16p65w/dsf916Ki4u1fv16TZ8+PSyB1KWkpESVlZXWsmPHjgb/TISfw+FQenq60tPT6fIFANTpuBKUESNGaM6cOVq0aFHQXPpZWVmqqanR3r17g+rv3LlTWVlZVp2dO3cesf3wttrEx8dbs8YyeywA4GTncDg0a9asSIchSZowYYLOO+882z+3XgmKMUYjRozQzJkztXDhQjVv3jxoe5cuXeTxeLRgwQJr3aZNm7R9+3YVFBRIkgoKCrRu3Trt2rXLqjNv3jwlJyerXbt2J3IsiHJ+v1+ffPKJPvnkE249BIAoFE2JUb2uQSkuLta0adM0e/ZsJSUlWdeMpKSkKCEhQSkpKRoyZIjGjBmjtLQ0JScna+TIkSooKFDXrl0lSVdccYXatWunW265RY899pgqKir0wAMPqLi4WPHx8eE/QkQNv9+v9957T5J03nnnMdU9ACCkevWgTJ48WZWVlerevbuys7Ot5c0337TqPPXUU7r66qvVr18/devWTVlZWZoxY4a13eVyac6cOXK5XCooKNDNN9+s3/72t3rkkUfCd1SISk6nU+3atVO7du24gA5A1OnevbtGjhypUaNG6cwzz1RmZqb+8pe/6MCBA7r11luVlJSkVq1aWT+0pJ9+eA0ZMkTNmzdXQkKCWrdurWeeecbafujQIZ177rkaNmyYtW7r1q1KSkrSK6+8csyx7dixQ7/5zW+UmpqqtLQ0XXfddfr666+t7YMHD1afPn30xBNPKDs7W+np6SouLpbX67XqlJeX66qrrlJCQoKaN2+uadOmqVmzZnr66aclSc2aNZMkXX/99XI4HNbrw/72t7+pWbNmSklJ0YABA7Rv375jjv+4mBhUWVlpJJnKyspIhwIA+Jkff/zRbNiwwfz4449HbKuurjbV1dUmEAhY63w+n6murjZerzesdY/HZZddZpKSksyjjz5qvvzyS/Poo48a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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 选择 max_length\n",
    "length_collect = {}\n",
    "for text in train_data:\n",
    "    length = len(text)\n",
    "    length_collect[length] = length_collect.get(length, 0) + 1\n",
    "    \n",
    "MAX_LENGTH = 500\n",
    "plt.bar(length_collect.keys(), length_collect.values())\n",
    "plt.axvline(MAX_LENGTH, label=\"max length\", c=\"gray\", ls=\":\")\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Tokenizer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T10:44:33.920674Z",
     "start_time": "2025-01-24T10:44:33.241435Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-24T10:48:05.483630Z",
     "iopub.status.busy": "2025-01-24T10:48:05.483388Z",
     "iopub.status.idle": "2025-01-24T10:48:05.517993Z",
     "shell.execute_reply": "2025-01-24T10:48:05.517524Z",
     "shell.execute_reply.started": "2025-01-24T10:48:05.483610Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "raw text\n",
      "['hello', 'world']\n",
      "['tokenize', 'text', 'datas', 'with', 'batch']\n",
      "['this', 'is', 'a', 'test']\n",
      "indices\n",
      "tensor([   0,    0,    0,    1, 4825,  182,    3])\n",
      "tensor([    1,     2,  3004,     2,    19, 19233,     3])\n",
      "tensor([   0,    1,   14,    9,    6, 2181,    3])\n",
      "decode text\n",
      "[PAD] [PAD] [PAD] [BOS] hello world [EOS]\n",
      "[BOS] [UNK] text [UNK] with batch [EOS]\n",
      "[PAD] [BOS] this is a test [EOS]\n"
     ]
    }
   ],
   "source": [
    "class Tokenizer:\n",
    "    def __init__(self, word2idx, idx2word, max_length=500, pad_idx=0, bos_idx=1, eos_idx=3, unk_idx=2):\n",
    "        self.word2idx = word2idx\n",
    "        self.idx2word = idx2word\n",
    "        self.max_length = max_length\n",
    "        self.pad_idx = pad_idx\n",
    "        self.bos_idx = bos_idx\n",
    "        self.eos_idx = eos_idx\n",
    "        self.unk_idx = unk_idx\n",
    "    \n",
    "    def encode(self, text_list, padding_first=False):\n",
    "        \"\"\"如果padding_first == True，则padding加载前面，否则加载后面\"\"\"\n",
    "        max_length = min(self.max_length, 2 + max([len(text) for text in text_list]))\n",
    "        indices_list = []\n",
    "        for text in text_list:\n",
    "            indices = [self.bos_idx] + [self.word2idx.get(word, self.unk_idx) for word in text[:max_length-2]] + [self.eos_idx]\n",
    "            if padding_first:\n",
    "                indices = [self.pad_idx] * (max_length - len(indices)) + indices\n",
    "            else:\n",
    "                indices = indices + [self.pad_idx] * (max_length - len(indices))\n",
    "            indices_list.append(indices)\n",
    "        return torch.tensor(indices_list)\n",
    "    \n",
    "    \n",
    "    def decode(self, indices_list, remove_bos=True, remove_eos=True, remove_pad=True, split=False):\n",
    "        text_list = []\n",
    "        for indices in indices_list:\n",
    "            text = []\n",
    "            for index in indices:\n",
    "                word = self.idx2word.get(index, \"[UNK]\")\n",
    "                if remove_bos and word == \"[BOS]\":\n",
    "                    continue\n",
    "                if remove_eos and word == \"[EOS]\":\n",
    "                    break\n",
    "                if remove_pad and word == \"[PAD]\":\n",
    "                    break\n",
    "                text.append(word)\n",
    "            text_list.append(\" \".join(text) if not split else text)\n",
    "        return text_list\n",
    "    \n",
    "\n",
    "tokenizer = Tokenizer(word2idx=word2idx, idx2word=idx2word)\n",
    "raw_text = [\"hello world\".split(), \"tokenize text datas with batch\".split(), \"this is a test\".split()]\n",
    "indices = tokenizer.encode(raw_text, padding_first=True)\n",
    "decode_text = tokenizer.decode(indices.tolist(), remove_bos=False, remove_eos=False, remove_pad=False)\n",
    "print(\"raw text\")\n",
    "for raw in raw_text:\n",
    "    print(raw)\n",
    "print(\"indices\")\n",
    "for index in indices:\n",
    "    print(index)\n",
    "print(\"decode text\")\n",
    "for decode in decode_text:\n",
    "    print(decode)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T10:44:33.932609Z",
     "start_time": "2025-01-24T10:44:33.922731Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-24T10:48:05.518737Z",
     "iopub.status.busy": "2025-01-24T10:48:05.518547Z",
     "iopub.status.idle": "2025-01-24T10:48:05.522743Z",
     "shell.execute_reply": "2025-01-24T10:48:05.522251Z",
     "shell.execute_reply.started": "2025-01-24T10:48:05.518717Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[\"[BOS] this film was just brilliant casting location scenery story direction everyone's really suited the part they played and you could just imagine being there robert [UNK] is an amazing actor and now the same being director [UNK] father came from the same scottish island as myself so i loved the fact there was a real connection with this film the witty remarks throughout the film were great it was just brilliant so much that i bought the film as soon as it was released for [UNK] and would recommend it to everyone to watch and the fly fishing was amazing really cried at the end it was so sad and you know what they say if you cry at a film it must have been good and this definitely was also [UNK] to the two little boy's that played the [UNK] of norman and paul they were just brilliant children are often left out of the [UNK] list i think because the stars that play them all grown up are such a big profile for the whole film but these children are amazing and should be praised for what they have done don't you think the whole story was so lovely because it was true and was someone's life after all that was shared with us all\",\n",
       " \"[BOS] big hair big boobs bad music and a giant safety pin these are the words to best describe this terrible movie i love cheesy horror movies and i've seen hundreds but this had got to be on of the worst ever made the plot is paper thin and ridiculous the acting is an abomination the script is completely laughable the best is the end showdown with the cop and how he worked out who the killer is it's just so damn terribly written the clothes are sickening and funny in equal [UNK] the hair is big lots of boobs [UNK] men wear those cut [UNK] shirts that show off their [UNK] sickening that men actually wore them and the music is just [UNK] trash that plays over and over again in almost every scene there is trashy music boobs and [UNK] taking away bodies and the gym still doesn't close for [UNK] all joking aside this is a truly bad film whose only charm is to look back on the disaster that was the 80's and have a good old laugh at how bad everything was back then\"]"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 看看训练集的数据\n",
    "\n",
    "tokenizer.decode(train_data[:2], remove_bos=False, remove_eos=False, remove_pad=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数据集与 DataLoader"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T10:44:36.151333Z",
     "start_time": "2025-01-24T10:44:33.933616Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-24T10:48:05.523573Z",
     "iopub.status.busy": "2025-01-24T10:48:05.523264Z",
     "iopub.status.idle": "2025-01-24T10:48:08.873380Z",
     "shell.execute_reply": "2025-01-24T10:48:08.872829Z",
     "shell.execute_reply.started": "2025-01-24T10:48:05.523554Z"
    }
   },
   "outputs": [],
   "source": [
    "from torch.utils.data import Dataset, DataLoader\n",
    "\n",
    "class IMDBDataset(Dataset):\n",
    "    def __init__(self, data, labels, remain_length=True):\n",
    "        if remain_length:\n",
    "            self.data = tokenizer.decode(data, remove_bos=False, remove_eos=False, remove_pad=False)\n",
    "        else:\n",
    "            # 缩减一下数据\n",
    "            self.data = tokenizer.decode(data)\n",
    "        self.labels = labels\n",
    "    \n",
    "    def __getitem__(self, index):\n",
    "        text = self.data[index]\n",
    "        label = self.labels[index]\n",
    "        return text, label\n",
    "    \n",
    "    def __len__(self):\n",
    "        return len(self.data)\n",
    "    \n",
    "    \n",
    "def collate_fct(batch):\n",
    "    text_list = [item[0].split() for item in batch]\n",
    "    label_list = [item[1] for item in batch]\n",
    "    # 这里使用 padding first\n",
    "    text_list = tokenizer.encode(text_list, padding_first=True).to(dtype=torch.int)\n",
    "    return text_list, torch.tensor(label_list).reshape(-1, 1).to(dtype=torch.float)\n",
    "\n",
    "\n",
    "# 用RNN，缩短序列长度\n",
    "train_ds = IMDBDataset(train_data, train_labels, remain_length=False)\n",
    "test_ds = IMDBDataset(test_data, test_labels, remain_length=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T10:44:36.157171Z",
     "start_time": "2025-01-24T10:44:36.152333Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-24T10:48:08.874555Z",
     "iopub.status.busy": "2025-01-24T10:48:08.874087Z",
     "iopub.status.idle": "2025-01-24T10:48:08.877568Z",
     "shell.execute_reply": "2025-01-24T10:48:08.877077Z",
     "shell.execute_reply.started": "2025-01-24T10:48:08.874530Z"
    }
   },
   "outputs": [],
   "source": [
    "batch_size = 128\n",
    "train_dl = DataLoader(train_ds, batch_size=batch_size, shuffle=True, collate_fn=collate_fct)\n",
    "test_dl = DataLoader(test_ds, batch_size=batch_size, shuffle=False, collate_fn=collate_fct)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T10:44:36.485753Z",
     "start_time": "2025-01-24T10:44:36.158170Z"
    },
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2025-01-24T10:48:08.878517Z",
     "iopub.status.busy": "2025-01-24T10:48:08.878191Z",
     "iopub.status.idle": "2025-01-24T10:48:08.917805Z",
     "shell.execute_reply": "2025-01-24T10:48:08.917260Z",
     "shell.execute_reply.started": "2025-01-24T10:48:08.878497Z"
    },
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([128, 500]) torch.Size([128, 1])\n"
     ]
    }
   ],
   "source": [
    "for text, label in train_dl: #检查样本是否存在问题\n",
    "    print(text.shape, label.shape)\n",
    "    break"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 定义模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T03:01:42.193751Z",
     "start_time": "2025-01-24T03:01:42.188880Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-24T10:48:08.918572Z",
     "iopub.status.busy": "2025-01-24T10:48:08.918389Z",
     "iopub.status.idle": "2025-01-24T10:48:08.928686Z",
     "shell.execute_reply": "2025-01-24T10:48:08.928255Z",
     "shell.execute_reply.started": "2025-01-24T10:48:08.918553Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================== 一层单向 LSTM ===================================\n",
      "            embeding.weight             paramerters num: 160000\n",
      "           lstm.weight_ih_l0            paramerters num: 4096\n",
      "           lstm.weight_hh_l0            paramerters num: 16384\n",
      "            lstm.bias_ih_l0             paramerters num: 256\n",
      "            lstm.bias_hh_l0             paramerters num: 256\n",
      "              layer.weight              paramerters num: 4096\n",
      "               layer.bias               paramerters num: 64\n",
      "               fc.weight                paramerters num: 64\n",
      "                fc.bias                 paramerters num: 1\n"
     ]
    }
   ],
   "source": [
    "class LSTM(nn.Module):\n",
    "    def __init__(self, embedding_dim=16, hidden_dim=64, vocab_size=vocab_size, num_layers=1, bidirectional=False):\n",
    "        super(LSTM, self).__init__()\n",
    "        self.embeding = nn.Embedding(vocab_size, embedding_dim)\n",
    "        self.lstm = nn.LSTM(embedding_dim, hidden_dim, num_layers=num_layers, batch_first=True, bidirectional=bidirectional)\n",
    "        self.layer = nn.Linear(hidden_dim * (2 if bidirectional else 1), hidden_dim)\n",
    "        self.fc = nn.Linear(hidden_dim, 1)\n",
    "        \n",
    "    def forward(self, x):\n",
    "        # [bs, seq length]\n",
    "        x = self.embeding(x)\n",
    "        # [bs, seq length, embedding_dim] -> shape [bs, seq length，hidden_dim]\n",
    "        seq_output, (hidden, cell) = self.lstm(x)\n",
    "        # print(f'seq_output.shape{seq_output.shape}')\n",
    "        # print(f'hidden.shape{hidden.shape}') #最后一个时间步的输出\n",
    "        # print(f'cell.shape{cell.shape}') #最后一个时间步的cell state\n",
    "        # print(seq_output[:, -1, :].squeeze()==hidden.squeeze()) #squeeze() 去掉轴的尺寸为1的哪个轴\n",
    "        # print(seq_output[:, -1, :].squeeze()==cell.squeeze())\n",
    "        x = seq_output[:, -1, :]\n",
    "        # 取最后一个时间步的输出 (这也是为什么要设置padding_first=True的原因)\n",
    "        x = self.layer(x)\n",
    "        x = self.fc(x)\n",
    "        return x\n",
    "    \n",
    "sample_inputs = torch.randint(0, vocab_size, (2, 128))\n",
    "    \n",
    "print(\"{:=^80}\".format(\" 一层单向 LSTM \"))       \n",
    "for key, value in LSTM().named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T03:01:45.697591Z",
     "start_time": "2025-01-24T03:01:45.613064Z"
    },
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2025-01-24T10:48:08.929611Z",
     "iopub.status.busy": "2025-01-24T10:48:08.929224Z",
     "iopub.status.idle": "2025-01-24T10:48:09.081197Z",
     "shell.execute_reply": "2025-01-24T10:48:09.080676Z",
     "shell.execute_reply.started": "2025-01-24T10:48:08.929591Z"
    },
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([128, 1])\n"
     ]
    }
   ],
   "source": [
    "model = LSTM()\n",
    "#随机一个（128,500）的输入\n",
    "sample_inputs = torch.randint(0, vocab_size, (128, 500))\n",
    "sample_outputs = model(sample_inputs)\n",
    "print(sample_outputs.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-07-30T02:15:50.096207800Z",
     "start_time": "2024-07-30T02:15:50.080216700Z"
    },
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2025-01-24T10:48:09.082100Z",
     "iopub.status.busy": "2025-01-24T10:48:09.081783Z",
     "iopub.status.idle": "2025-01-24T10:48:09.085455Z",
     "shell.execute_reply": "2025-01-24T10:48:09.084936Z",
     "shell.execute_reply.started": "2025-01-24T10:48:09.082080Z"
    },
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4096"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "64*64"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-02T08:36:09.545313600Z",
     "start_time": "2024-05-02T08:36:09.506335700Z"
    },
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2025-01-24T10:48:09.086323Z",
     "iopub.status.busy": "2025-01-24T10:48:09.085942Z",
     "iopub.status.idle": "2025-01-24T10:48:09.089380Z",
     "shell.execute_reply": "2025-01-24T10:48:09.088885Z",
     "shell.execute_reply.started": "2025-01-24T10:48:09.086303Z"
    },
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4096"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "4 * 16 * 64 #lstm.weight_ih_l0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-07-30T02:56:57.186572800Z",
     "start_time": "2024-07-30T02:56:57.168877900Z"
    },
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2025-01-24T10:48:09.090205Z",
     "iopub.status.busy": "2025-01-24T10:48:09.089859Z",
     "iopub.status.idle": "2025-01-24T10:48:09.093083Z",
     "shell.execute_reply": "2025-01-24T10:48:09.092609Z",
     "shell.execute_reply.started": "2025-01-24T10:48:09.090185Z"
    },
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "8192"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "128*64"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T03:03:33.941487Z",
     "start_time": "2025-01-24T03:03:33.937308Z"
    },
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2025-01-24T10:48:09.093860Z",
     "iopub.status.busy": "2025-01-24T10:48:09.093578Z",
     "iopub.status.idle": "2025-01-24T10:48:09.098683Z",
     "shell.execute_reply": "2025-01-24T10:48:09.098257Z",
     "shell.execute_reply.started": "2025-01-24T10:48:09.093841Z"
    },
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================== 一层双向 LSTM ===================================\n",
      "            embeding.weight             paramerters num: 160000\n",
      "           lstm.weight_ih_l0            paramerters num: 4096\n",
      "           lstm.weight_hh_l0            paramerters num: 16384\n",
      "            lstm.bias_ih_l0             paramerters num: 256\n",
      "            lstm.bias_hh_l0             paramerters num: 256\n",
      "       lstm.weight_ih_l0_reverse        paramerters num: 4096\n",
      "       lstm.weight_hh_l0_reverse        paramerters num: 16384\n",
      "        lstm.bias_ih_l0_reverse         paramerters num: 256\n",
      "        lstm.bias_hh_l0_reverse         paramerters num: 256\n",
      "              layer.weight              paramerters num: 8192\n",
      "               layer.bias               paramerters num: 64\n",
      "               fc.weight                paramerters num: 64\n",
      "                fc.bias                 paramerters num: 1\n"
     ]
    }
   ],
   "source": [
    "print(\"{:=^80}\".format(\" 一层双向 LSTM \"))\n",
    "for key, value in LSTM(bidirectional=True).named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T03:04:05.259754Z",
     "start_time": "2025-01-24T03:04:05.255731Z"
    },
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2025-01-24T10:48:09.099474Z",
     "iopub.status.busy": "2025-01-24T10:48:09.099179Z",
     "iopub.status.idle": "2025-01-24T10:48:09.105450Z",
     "shell.execute_reply": "2025-01-24T10:48:09.105008Z",
     "shell.execute_reply.started": "2025-01-24T10:48:09.099455Z"
    },
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================== 两层单向 LSTM ===================================\n",
      "            embeding.weight             paramerters num: 160000\n",
      "           lstm.weight_ih_l0            paramerters num: 4096\n",
      "           lstm.weight_hh_l0            paramerters num: 16384\n",
      "            lstm.bias_ih_l0             paramerters num: 256\n",
      "            lstm.bias_hh_l0             paramerters num: 256\n",
      "           lstm.weight_ih_l1            paramerters num: 16384\n",
      "           lstm.weight_hh_l1            paramerters num: 16384\n",
      "            lstm.bias_ih_l1             paramerters num: 256\n",
      "            lstm.bias_hh_l1             paramerters num: 256\n",
      "              layer.weight              paramerters num: 4096\n",
      "               layer.bias               paramerters num: 64\n",
      "               fc.weight                paramerters num: 64\n",
      "                fc.bias                 paramerters num: 1\n"
     ]
    }
   ],
   "source": [
    "print(\"{:=^80}\".format(\" 两层单向 LSTM \"))\n",
    "for key, value in LSTM(num_layers=2).named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T03:05:07.528779Z",
     "start_time": "2025-01-24T03:05:07.525030Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-24T10:48:09.106308Z",
     "iopub.status.busy": "2025-01-24T10:48:09.105949Z",
     "iopub.status.idle": "2025-01-24T10:48:09.109293Z",
     "shell.execute_reply": "2025-01-24T10:48:09.108778Z",
     "shell.execute_reply.started": "2025-01-24T10:48:09.106289Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4096"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "16*64*4 #4是4倍"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-24T03:05:23.241838Z",
     "start_time": "2025-01-24T03:05:23.239064Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-24T10:48:09.110101Z",
     "iopub.status.busy": "2025-01-24T10:48:09.109767Z",
     "iopub.status.idle": "2025-01-24T10:48:09.113043Z",
     "shell.execute_reply": "2025-01-24T10:48:09.112574Z",
     "shell.execute_reply.started": "2025-01-24T10:48:09.110082Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "16384"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "64*64*4"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-07-30T02:57:22.790960200Z",
     "start_time": "2024-07-30T02:57:22.446263Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-24T10:48:09.115704Z",
     "iopub.status.busy": "2025-01-24T10:48:09.115402Z",
     "iopub.status.idle": "2025-01-24T10:48:09.213699Z",
     "shell.execute_reply": "2025-01-24T10:48:09.213258Z",
     "shell.execute_reply.started": "2025-01-24T10:48:09.115685Z"
    }
   },
   "outputs": [],
   "source": [
    "from sklearn.metrics import accuracy_score\n",
    "\n",
    "@torch.no_grad()\n",
    "def evaluating(model, dataloader, loss_fct):\n",
    "    loss_list = []\n",
    "    pred_list = []\n",
    "    label_list = []\n",
    "    for datas, labels in dataloader:\n",
    "        datas = datas.to(device)\n",
    "        labels = labels.to(device)\n",
    "        # 前向计算\n",
    "        logits = model(datas)\n",
    "        loss = loss_fct(logits, labels)         # 验证集损失\n",
    "        loss_list.append(loss.item())\n",
    "        # 二分类\n",
    "        preds = logits > 0\n",
    "        pred_list.extend(preds.cpu().numpy().tolist())\n",
    "        label_list.extend(labels.cpu().numpy().tolist())\n",
    "        \n",
    "    acc = accuracy_score(label_list, pred_list)\n",
    "    return np.mean(loss_list), acc\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### TensorBoard 可视化\n",
    "\n",
    "\n",
    "训练过程中可以使用如下命令启动tensorboard服务。\n",
    "\n",
    "```shell\n",
    "tensorboard \\\n",
    "    --logdir=runs \\     # log 存放路径\n",
    "    --host 0.0.0.0 \\    # ip\n",
    "    --port 8848         # 端口\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-24T10:48:09.214521Z",
     "iopub.status.busy": "2025-01-24T10:48:09.214172Z",
     "iopub.status.idle": "2025-01-24T10:48:09.357064Z",
     "shell.execute_reply": "2025-01-24T10:48:09.356458Z",
     "shell.execute_reply.started": "2025-01-24T10:48:09.214500Z"
    }
   },
   "outputs": [],
   "source": [
    "from torch.utils.tensorboard import SummaryWriter\n",
    "\n",
    "\n",
    "class TensorBoardCallback:\n",
    "    def __init__(self, log_dir, flush_secs=10):\n",
    "        \"\"\"\n",
    "        Args:\n",
    "            log_dir (str): dir to write log.\n",
    "            flush_secs (int, optional): write to dsk each flush_secs seconds. Defaults to 10.\n",
    "        \"\"\"\n",
    "        self.writer = SummaryWriter(log_dir=log_dir, flush_secs=flush_secs)\n",
    "\n",
    "    def draw_model(self, model, input_shape):\n",
    "        self.writer.add_graph(model, input_to_model=torch.randn(input_shape))\n",
    "        \n",
    "    def add_loss_scalars(self, step, loss, val_loss):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/loss\", \n",
    "            tag_scalar_dict={\"loss\": loss, \"val_loss\": val_loss},\n",
    "            global_step=step,\n",
    "            )\n",
    "        \n",
    "    def add_acc_scalars(self, step, acc, val_acc):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/accuracy\",\n",
    "            tag_scalar_dict={\"accuracy\": acc, \"val_accuracy\": val_acc},\n",
    "            global_step=step,\n",
    "        )\n",
    "        \n",
    "    def add_lr_scalars(self, step, learning_rate):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/learning_rate\",\n",
    "            tag_scalar_dict={\"learning_rate\": learning_rate},\n",
    "            global_step=step,\n",
    "            \n",
    "        )\n",
    "    \n",
    "    def __call__(self, step, **kwargs):\n",
    "        # add loss\n",
    "        loss = kwargs.pop(\"loss\", None)\n",
    "        val_loss = kwargs.pop(\"val_loss\", None)\n",
    "        if loss is not None and val_loss is not None:\n",
    "            self.add_loss_scalars(step, loss, val_loss)\n",
    "        # add acc\n",
    "        acc = kwargs.pop(\"acc\", None)\n",
    "        val_acc = kwargs.pop(\"val_acc\", None)\n",
    "        if acc is not None and val_acc is not None:\n",
    "            self.add_acc_scalars(step, acc, val_acc)\n",
    "        # add lr\n",
    "        learning_rate = kwargs.pop(\"lr\", None)\n",
    "        if learning_rate is not None:\n",
    "            self.add_lr_scalars(step, learning_rate)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Save Best\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-24T10:48:09.357981Z",
     "iopub.status.busy": "2025-01-24T10:48:09.357731Z",
     "iopub.status.idle": "2025-01-24T10:48:09.363162Z",
     "shell.execute_reply": "2025-01-24T10:48:09.362596Z",
     "shell.execute_reply.started": "2025-01-24T10:48:09.357960Z"
    }
   },
   "outputs": [],
   "source": [
    "class SaveCheckpointsCallback:\n",
    "    def __init__(self, save_dir, save_step=5000, save_best_only=True):\n",
    "        \"\"\"\n",
    "        Save checkpoints each save_epoch epoch. \n",
    "        We save checkpoint by epoch in this implementation.\n",
    "        Usually, training scripts with pytorch evaluating model and save checkpoint by step.\n",
    "\n",
    "        Args:\n",
    "            save_dir (str): dir to save checkpoint\n",
    "            save_epoch (int, optional): the frequency to save checkpoint. Defaults to 1.\n",
    "            save_best_only (bool, optional): If True, only save the best model or save each model at every epoch.\n",
    "        \"\"\"\n",
    "        self.save_dir = save_dir\n",
    "        self.save_step = save_step\n",
    "        self.save_best_only = save_best_only\n",
    "        self.best_metrics = -1\n",
    "        \n",
    "        # mkdir\n",
    "        if not os.path.exists(self.save_dir):\n",
    "            os.mkdir(self.save_dir)\n",
    "        \n",
    "    def __call__(self, step, state_dict, metric=None):\n",
    "        if step % self.save_step > 0:\n",
    "            return\n",
    "        \n",
    "        if self.save_best_only:\n",
    "            assert metric is not None\n",
    "            if metric >= self.best_metrics:\n",
    "                # save checkpoints\n",
    "                torch.save(state_dict, os.path.join(self.save_dir, \"best.ckpt\"))\n",
    "                # update best metrics\n",
    "                self.best_metrics = metric\n",
    "        else:\n",
    "            torch.save(state_dict, os.path.join(self.save_dir, f\"{step}.ckpt\"))\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Early Stop"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-24T10:48:09.363945Z",
     "iopub.status.busy": "2025-01-24T10:48:09.363779Z",
     "iopub.status.idle": "2025-01-24T10:48:09.368109Z",
     "shell.execute_reply": "2025-01-24T10:48:09.367574Z",
     "shell.execute_reply.started": "2025-01-24T10:48:09.363927Z"
    }
   },
   "outputs": [],
   "source": [
    "class EarlyStopCallback:\n",
    "    def __init__(self, patience=5, min_delta=0.01):\n",
    "        \"\"\"\n",
    "\n",
    "        Args:\n",
    "            patience (int, optional): Number of epochs with no improvement after which training will be stopped.. Defaults to 5.\n",
    "            min_delta (float, optional): Minimum change in the monitored quantity to qualify as an improvement, i.e. an absolute \n",
    "                change of less than min_delta, will count as no improvement. Defaults to 0.01.\n",
    "        \"\"\"\n",
    "        self.patience = patience\n",
    "        self.min_delta = min_delta\n",
    "        self.best_metric = -1\n",
    "        self.counter = 0\n",
    "        \n",
    "    def __call__(self, metric):\n",
    "        if metric >= self.best_metric + self.min_delta:\n",
    "            # update best metric\n",
    "            self.best_metric = metric\n",
    "            # reset counter \n",
    "            self.counter = 0\n",
    "        else: \n",
    "            self.counter += 1\n",
    "            \n",
    "    @property\n",
    "    def early_stop(self):\n",
    "        return self.counter >= self.patience\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2025-01-24T11:05:08.158958Z",
     "iopub.status.busy": "2025-01-24T11:05:08.158610Z",
     "iopub.status.idle": "2025-01-24T11:08:01.259160Z",
     "shell.execute_reply": "2025-01-24T11:08:01.258676Z",
     "shell.execute_reply.started": "2025-01-24T11:05:08.158934Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 3920/3920 [02:53<00:00, 22.65it/s, epoch=19]\n"
     ]
    }
   ],
   "source": [
    "# 训练\n",
    "def training(\n",
    "    model, \n",
    "    train_loader, \n",
    "    val_loader, \n",
    "    epoch, \n",
    "    loss_fct, \n",
    "    optimizer, \n",
    "    tensorboard_callback=None,\n",
    "    save_ckpt_callback=None,\n",
    "    early_stop_callback=None,\n",
    "    eval_step=500,\n",
    "    ):\n",
    "    record_dict = {\n",
    "        \"train\": [],\n",
    "        \"val\": []\n",
    "    }\n",
    "    \n",
    "    global_step = 0\n",
    "    model.train()\n",
    "    with tqdm(total=epoch * len(train_loader)) as pbar:\n",
    "        for epoch_id in range(epoch):\n",
    "            # training\n",
    "            for datas, labels in train_loader:\n",
    "                datas = datas.to(device)\n",
    "                labels = labels.to(device)\n",
    "                # 梯度清空\n",
    "                optimizer.zero_grad()\n",
    "                # 模型前向计算\n",
    "                logits = model(datas)\n",
    "                # 计算损失\n",
    "                loss = loss_fct(logits, labels)\n",
    "                # 梯度回传\n",
    "                loss.backward()\n",
    "                # 调整优化器，包括学习率的变动等\n",
    "                optimizer.step()\n",
    "                preds = logits > 0\n",
    "            \n",
    "                acc = accuracy_score(labels.cpu().numpy(), preds.cpu().numpy())    \n",
    "                loss = loss.cpu().item()\n",
    "                # record\n",
    "                \n",
    "                record_dict[\"train\"].append({\n",
    "                    \"loss\": loss, \"acc\": acc, \"step\": global_step\n",
    "                })\n",
    "                \n",
    "                # evaluating\n",
    "                if global_step % eval_step == 0:\n",
    "                    model.eval()\n",
    "                    val_loss, val_acc = evaluating(model, val_loader, loss_fct)\n",
    "                    record_dict[\"val\"].append({\n",
    "                        \"loss\": val_loss, \"acc\": val_acc, \"step\": global_step\n",
    "                    })\n",
    "                    model.train()\n",
    "                    \n",
    "                    # 1. 使用 tensorboard 可视化\n",
    "                    if tensorboard_callback is not None:\n",
    "                        tensorboard_callback(\n",
    "                            global_step, \n",
    "                            loss=loss, val_loss=val_loss,\n",
    "                            acc=acc, val_acc=val_acc,\n",
    "                            lr=optimizer.param_groups[0][\"lr\"],\n",
    "                            )\n",
    "                \n",
    "                    # 2. 保存模型权重 save model checkpoint\n",
    "                    if save_ckpt_callback is not None:\n",
    "                        save_ckpt_callback(global_step, model.state_dict(), metric=val_acc)\n",
    "\n",
    "                    # 3. 早停 Early Stop\n",
    "                    if early_stop_callback is not None:\n",
    "                        early_stop_callback(val_acc)\n",
    "                        if early_stop_callback.early_stop:\n",
    "                            print(f\"Early stop at epoch {epoch_id} / global_step {global_step}\")\n",
    "                            return record_dict\n",
    "                    \n",
    "                # udate step\n",
    "                global_step += 1\n",
    "                pbar.update(1)\n",
    "                pbar.set_postfix({\"epoch\": epoch_id})\n",
    "        \n",
    "    return record_dict\n",
    "        \n",
    "\n",
    "epoch = 20\n",
    "\n",
    "model = LSTM(bidirectional=True)\n",
    "\n",
    "# 1. 定义损失函数 采用交叉熵损失 (但是二分类)\n",
    "loss_fct = F.binary_cross_entropy_with_logits\n",
    "# 2. 定义优化器 采用 adam\n",
    "# Optimizers specified in the torch.optim package\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.001)\n",
    "\n",
    "# 1. tensorboard 可视化\n",
    "if not os.path.exists(\"runs\"):\n",
    "    os.mkdir(\"runs\")\n",
    "tensorboard_callback = TensorBoardCallback(\"runs/imdb-lstm\")\n",
    "# tensorboard_callback.draw_model(model, [1, MAX_LENGTH])\n",
    "# 2. save best\n",
    "if not os.path.exists(\"checkpoints\"):\n",
    "    os.makedirs(\"checkpoints\")\n",
    "save_ckpt_callback = SaveCheckpointsCallback(\"checkpoints/imdb-lstm\", save_step=len(train_dl), save_best_only=True)\n",
    "# 3. early stop\n",
    "early_stop_callback = EarlyStopCallback(patience=10)\n",
    "\n",
    "model = model.to(device)\n",
    "record = training(\n",
    "    model, \n",
    "    train_dl, \n",
    "    test_dl, \n",
    "    epoch, \n",
    "    loss_fct, \n",
    "    optimizer, \n",
    "    tensorboard_callback=tensorboard_callback,\n",
    "    save_ckpt_callback=save_ckpt_callback,\n",
    "    early_stop_callback=early_stop_callback,\n",
    "    eval_step=len(train_dl)\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2025-01-24T11:08:01.260528Z",
     "iopub.status.busy": "2025-01-24T11:08:01.260094Z",
     "iopub.status.idle": "2025-01-24T11:08:01.263925Z",
     "shell.execute_reply": "2025-01-24T11:08:01.263501Z",
     "shell.execute_reply.started": "2025-01-24T11:08:01.260506Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'loss': 0.08886099606752396, 'acc': 0.975, 'step': 3919}"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "record['train'][-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-24T11:08:01.264627Z",
     "iopub.status.busy": "2025-01-24T11:08:01.264464Z",
     "iopub.status.idle": "2025-01-24T11:08:01.451953Z",
     "shell.execute_reply": "2025-01-24T11:08:01.451352Z",
     "shell.execute_reply.started": "2025-01-24T11:08:01.264608Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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BWRmZpKSkkKvXr34/fff/fYX6AZkMBj44IMPuOiii0hKSqJNmzb89NNPZR7X7777jpNPPhmbzUbz5s0ZP3683/q33nqLNm3akJCQQGZmJpdeeqlv3bfffkvnzp1JTEykbt26DBo0iIKCgjL3RSgfeueI9zdc0X/RniNV+fxwu93cdNNNtGjRgsTERNq1a8drr70W1G7y5Mm+c6Zhw4aMGTPGt+7YsWPceuutZGZmkpCQQKdOnfjll1+iOr4g1CQKHS5u/mgp3y7bE9f9Tpi1iXFT/43pvlwViNlNbsKECYwePZpRo0YB8M477zBt2jQmT57Mgw8+GNS+Tp06fu+//PJLkpKSapwY2pSVz+eL1ADdsYPbHufeCELlUuR00/Gx347Lsdc9NZQka3SXstdee41NmzbRqVMnnnrqKQDWrl0LwIMPPsj//vc/WrZsSe3atdm9ezfDhw/n2WefxWaz8fHHHzNixAg2btzISSedFPIYTz75JC+99BIvv/wyb7zxBtdccw07d+4MuhZGYtmyZVx++eU88cQTXHHFFcyfP5877riDunXrMnLkSJYuXcp//vMfPvnkE/r168eRI0f4559/ADVhwFVXXcVLL73ERRddRF5eHv/880+1u0HVJKrDOVKVzw9FUWjSpAnffPMNdevWZf78+dxyyy1kZmZyzjnnAPD2228zduxYXnjhBYYNG0ZOTg7z5s3zbT9s2DDy8vL49NNPadWqFevWrcNkMkU1hoJQk/hkwU5+X5/F7+uzuLRHk7jsU1E8vD57MwDXntqMkxvVist+K4OYxJDD4WDZsmWMGzfOt8xoNDJo0CAWLFgQ1T4mTZrElVdeGdaP2G63Y7fbfe+9VWadTidOpzOWLvu283ggv6iYlJi3jo68otL+lqWP1QHv56qpn6+yqAnjqJ5THhRF8f0dL2I5fmpqKlarlcTERDIyMgBYt24dAE888QQDBw70tU1PT6dz586+908++STff/89P/74I3feeadvuXccvNxwww1cccUVADzzzDO8/vrrLFy40DdhC/c5tJ9n/PjxDBgwgIcffhiA1q1bs3btWl5++WWuv/56duzYQXJyMsOHDyc1NZWmTZvStWtXFEVh7969uFwuLrzwQt/E9OSTT/Y7jrfv3v8ejwen0xk0OazOv1MhNmrVqoXVaiUpKYkGDRoAsGHDBgCeeuopBg8e7Gtbp04dunbt6nv/9NNP8/333/PTTz/5WWMCGTlyJFdddRUAzz33HK+//jqLFy+OeH5YLBaefPJJ3/sWLVqwYMECvvnmG9+2zzzzDPfddx933323r12vXr0A+P3331m8eDHr16+nbVv1gWXLli0jD4og1EDy7dG5usZCodPte51XHP/9VyQxiaHs7GzcbjeZmZl+yzMzM30XzHAsXryYNWvWMGnSpLDtnn/+eb+LnpeZM2eW2f941l4DY5//i9HtFBYfMtAqzcMZDeL3lHRHHniHc9q06RgMcdt1lWPWrFnHuws1guo8jmazmQYNGpCfn4/D4cDj8bBg7KnHpS/OogJyi6M/4VwuFw6Hw/eQpbCwEIB27dr5loFau+bFF19k5syZHDhwALfbTVFREZs3b/a1UxSF4uJiv+1at27t9z41NZVdu3b5LdPD24+8vDyMRiNr165l+PDhftt1796d1157jaNHj9KnTx+aNGlCq1atGDhwIAMHDuS8884jKSmJFi1acNZZZ9G1a1cGDBjA2WefzQUXXEB6errusQsKCigqKuLvv/8Oigfx9ksoH4kWE+ueKk3drSgKebl5pKalVnhxz0RL+a0fPXv29Hufn5/PE088wbRp09i/fz8ul4uioiK/FOZ6dOnSxfc6OTmZtLS0kG72gUycOJHJkyeza9cuioqKcDgcdOvWDYCDBw+yb98+vwcaWlauXEmTJk18QkgQTmQS4nBNCCRfI4AKHTVYDJWXSZMm0blzZ3r37h223bhx4xg7dqzvfW5uLk2bNmXIkCGkpaXFdEyHS+HX1fuYtkB9+vvuBvUHsOIwPH/jEJ6dvoFNB/OZdN0pmE1lvyGt2HWMV9aoiSTOGTYMk7HmqSGn08msWbMYPHgwFovleHen2lITxrG4uJjdu3eTkpJCQkICAJVpEPd4POTl5ZGamoohxicPZrMZq9Xqu5Z4H7A0aNDA7/ry3//+l99//52XXnqJ1q1bk5iYyOWXX47BYPC1MxqNJCQk+G2Xlpbm995oNPodLxTefqSmppKWlobJZMJms/ltl5iY6DtG7dq1WbFiBXPmzGHWrFm8+OKLvPzyyyxatIjatWsze/Zs5s+fz6xZs5g0aRLPPvssCxYsoEWLFkHjmJycTGJiImeeeabv+/QSScQJ0WEwGPxc1RRFwWU1kWQ1V7gYigeB3hz3338/s2bN4n//+5/v/Lj00ktxOBxh9xN4zTMYDFFZdr/88kvuv/9+xo8fT9++fUlNTfX93qH03AhFpPWCcCKhFUMejyfm+6ge+fZSL4IjBdXLoyAmMVSvXj1MJhNZWVl+y7Oysnwm9VAUFBTw5Zdf+vyQw2Gz2bDZbEHLLRZLzJPHDxds5dXpK4GEoHUGo4kpC9SnWCv35tO3Vd2Y9q3FZC79YRlNZizmqn9zKytl+R6EYKrzOLrdbgwGA0aj8bhM5LyTJ28fYsFqtaIoim877X/tvubPn8/IkSO55JJLAPVJ+I4dO+jfv79fu8A+6I1JNOMU2I8OHTowf/58v+0WLFhA27Ztfb8bq9XKkCFDGDJkCE888QTp6enMmTOHiy++GIAzzjiDM844g8cff5xmzZrx448/+j1o0o6jwWDQ/U1W19+oUDasVitutztiu3nz5jFy5EguuugioPT8qCjmzZtHv379uOOOO3zLtm7d6nudmppK8+bNmT17NmeffXbQ9l26dGHPnj1s2rRJrEPHiSMFDp7+ZR2X92xarvmWUH4SLKX3lWKnQqLV31L05eJdrN2Xy5Pnn4yx5OG+x+PhiZ/W0qFhGlf2Lo0LPJBTzPO/rqdb03TfsiMFdqoTMc0irFYrPXr0YPbs2b5liqIwe/Zs+vbtG3bbb775BrvdzrXXXlu2npaRS1sbmGl7gFtMPwet23G4NLNSeQ052rhkRYKUBaHK0rx5cxYtWsSOHTvIzs4O+VS6TZs2TJ06lZUrV7Jq1SquvvrqSo2Nuu+++5g9ezZPP/00mzZt4qOPPuLNN9/k/vvvB+CXX37h9ddfZ+XKlezcuZOPP/4YRVFo164dixYt4rnnnmPp0qXs2rWLqVOncujQITp06FBp/ReqJ1X1/GjTpg1Lly7lt99+Y9OmTTz66KMsWbLEr80TTzzB+PHjef3119m8eTPLly/njTfeAOCss87izDPP5JJLLmHWrFls376dX3/9lRkzZlRYnwV/nvllHd+v2MtV7y883l054bFqPKHy7MFWnJd+28gnC3eyYvcx37I5mw7x0YKdPDh1tV/b+75ZyY8r9/Hkz+t8y6qbZSjmR7pjx47l/fff56OPPmL9+vXcfvvtFBQU+LLLXX/99X4JFrxMmjSJCy+8kLp1K/dpQJ2dM2hiyOYhyxfca/4GKBUqa/eVun+4lfIJGO3mooUEoepy//33YzKZ6NixI/Xr1w8Z4zBhwgRq165Nv379GDFiBEOHDuWUU06ptH6ecsopfP3113z55Zd06tSJxx57jKeeeoqRI0cCaoKHqVOnMmDAADp06MA777zDF198wcknn0xaWhp///03w4cPp23btjzyyCOMHz+eYcOGVVr/hepJVT0/br31Vi6++GKuuOIK+vTpw+HDh/2sRKAmL3n11Vd56623OPnkkznvvPPYvHmzb/13331Hr169uOqqq+jYsSMPPPBAVFYwIT5oH0ALxxftnDc/INmBy61wpEB1d91yMM+3/GBuse6+1u0LdqWubpahmGOGrrjiCg4dOsRjjz3GgQMH6NatGzNmzPAlVdi1a1eQO8jGjRuZO3cuM2fOjE+vY6HvHeTk5lBrwQvcbf6e9rXh1kOXAgbW7y/9kgsc5bsgaq1BblFDglBladu2bVD2S6/A0NK8eXP++OMPv2XaLHJAkFuQXurqY8eORdWv/v37B21/ySWX+Nz0Ajn99NOZM2eO7roOHTrIE2+hTFTV88Nms/Hhhx/y4Ycf+i1/9tln/eLabr31Vm699VbdfdSpU4fJkydHdTwh/pTzmbMQR1yaL6PA7j//PVZUatXZnJXve13s1Lf86i33iqnqQpkSKIwZMyZk6ky9m3O7du2Oa32LpAH38+/ufXTZ8zFD877no3pFjMq+lnX7Sy+g5c18IW5ygiAIgiAI+sjcqOrgcpcKmEA3Oa2Q2XKoVAzZXfpGA73l1U0M1dwo/wC21x+Ea8SbYDByVv4MXre8yYJN+33rA5VxrGjFnuf4lVwRBKGKctttt5GSkqL7d9tttx3v7gnCcUXOj5pPdRNDHo+H137fzE+r9pV7XxP/3MIPK/bGoVfxwRXGTe5wfqmQWbjtMI/+sIb1+3OxO4Nr1IG+xW/13hzu/2YV46au5rXfN/PJwp1x7H38qdTU2scbT5crITEN9zc3cp5pIYnYucN5N3as5bYMaX8M4iYnCEIgTz31lC/5QSCxlgwQhJqGnB81n+NYm7tM7DpSyCu/b6JWooXzuzYq837W7M3h5d82AnBh98bx6l658BNDAQVYjxaWiqFip8InC3fyw4q9XN+vmd/2FlPozGNOt4dvl+3xW3Zlr6ZYylHCpiI5ocQQAB0v4LfOrzBg1VgGmlbwIS8x2nlfuS1Dip9KFjEkCII/GRkZZGRkHO9uCEKVRM6Pmk91mxt5RUJOkRO7y43NXLZCpVpxUVXQuskVBIihwzoubnl2l19skMvtIda6rU63UmXFUNXsVQVz2jlX8XbTl8nzJNLPtI5Prc+jFB4u1z61mTmq2wkvCIIgCIJQkVS3uZHDVTr5j1cMzPGMn9eitQzlBYihI/n6n1UrmpxlMPM5XVXjs+txQoqhWkkW7r15FK82epmjnhS6G7dw1bo7If9gmfep/WFVN1OwIAiCIAhCRVLeEiaVTUWIoaoyBi536JihUJasDQdKMzBrt48Wh7vqTo5PSDHk5f9uvJrPO7zNQU86DYq3wIfD4NjuMu3LrVFA1e3phyAIgiAIQkUSz6nRgZxiJszaRFaI2jfxQDt5L48Y0n5uV4xiqMDu4rXfN7MpK89v+dZD+UyYtYlPF+7ku4DYnGjQWna0MUNZucVMmb9Dd5vVe3N8r11lEDZOEUNVkwSLibTmXbnM8RiHzRlwuEQQHd4a875c4iYnCIIgCIKgSzznRjd9tITXZ29m9MdL47bPQJxxEkOh9hkN/5u5kVd+38SQV/72Wz5w/F+8Pnszj/ywhvu+WcW+Y0Ux7detsezkaSxDnywozfp2WY8m/tto5rleoRiL25+IoSpMstXETk8Dnqo/Aeq2hpzd8OEwCvesjsmc6RY3OUEQBEEQBF3i6SG2dp9aJ/LfPTkRWpadeLnJGTRJ15wxupct33k0qnaBlqNIaB/gaz/bsSL1dYO0BJ67uDOvXtGN01rXDd6+5HMUOcMnH7uwW2kWPhFDVZgkq5pQb49SF0b9CpmdID8L+/vn8OQ7n0S9H63/pFiGBKHm0rx5c1599dWo2hoMBn744YcK7Y8gVCViOT+EE4vqNjeyx0kMaR+Wx+pepicgtSLNy+4jhTHt16Xof7Yih7p85GnNsZiMXNi9Md2apofcPjDeKJAuTdKpn2or6XfV/f5PeDGUbFNzAxbYXZCSASN/4VCtztQ25PN/WQ/Ajnn8tekQXyzeFXY/kk1OEARBEARBH6WKJA+IFq3o0Es3HS3ah+XOGMdAbz6583BB0LKth4KXRdsnPzHkVMVNkrU0b3aKzRK0vdfCFZiJLhCLyYDFaCjZRixDVRbvF55b5FQXJNZmdq/3mO/uSKqhCM+nFzN5yvuMm7qaNXtDm2P9Y4YqtMuCIAiCIAhx4WBeMR8t2Elh+WrPk51vZ/Lc7RwLkY0scG706+r9vPzbBjYcyC3fgcvJzsMFfLxgB8UBLl/aBApHyyCGDuYV8+G87RzRjEc4y5Bb8fDpwp0+l7c/Nxz0uQNq2XwwP2jZlPk72Hm4gMXbj/DCrxuYtyXb/7O4FKbM286ObFU0OUOJIYc6BgmaIkIpCcElSb1iKpJlyGQ0YjEbS44pYqjK4nWT25dTzJM/r+XtOVt58JftjHI+wGx3dwyuYt63/I8hxiXs0FHjXiSbnHBC4/GAo6By/5yF6v8Yzrf33nuPRo0aoQQE9l1wwQXceOONbN26lQsuuIDMzExSUlLo1asXv//+e9yGafXq1QwYMIDExETq1q3LLbfcQn5+6Y1tzpw59O7dm+TkZNLT0znttNPYuVMNaF21ahVnn302qamppKWl0aNHD5YurbjgYSHO6J0j3t9wRf9FeY5U9vkxYcIEOnfuTHJyMk2bNuWOO+7wOx8A5s2bR//+/UlKSqJ27doMHTqUo0fVOApFUXj55Zc55ZRTSExM5KSTTuLZZ58tc39OVK77YDHPTN/Il1vLNyW89oNFPPXLOp7+Zb3ueu3c6Fihg9s/W87EP7fy+I9ry3Xc8nL2/+bw2I9rmTR3u9/y8lqGrp+0mCd/XscD3/7rWxYuZujrpbt55Ic1DHnlb4qdbkZNWaLbLtRc9IVfNzDqw8W889dWbgzY9rXZm3ji53Vc/u4CwH/OWuR0+0SQNwYoUSOGUm3BYsibjS4vghgymwy+QquxxktVJsGf8AQjRfMlf75ol89H1I6VW5338m2dKXTL+YPnLR/w9YFLoEsj3f1INjnhhMZZCM/pnxsVgRFI9755aB9Yk6Pa7rLLLuOuu+7izz//ZODAgQAcOXKEGTNmMH36dPLz8xk+fDjPPvssNpuNjz/+mBEjRrBx40ZOOumkcvW5oKCAoUOH0rdvX5YsWcLBgwe5+eabGTNmDFOmTMHlcnHhhRcyevRovvjiCxwOB4sXL8ZQEn17zTXX0L17d95++21MJhMrV67EYgl2XxCqKAHniN9vuKKJ8hyp7PPDaDTy+uuv06JFC7Zt28Ydd9zBAw88wFtvvQXAypUrGThwIDfeeCOvvfYaZrOZP//8E7dbnbCNGzeO999/n2effZZBgwaRlZXFhg0bYu7Hic7GEkvEmqOGCC3D461DM3fLId312rmRdhKdG2FCXdF4p28rdvknKyhvAgVtXR4vrjAZtlbtPhbV8XKL9Mdr1e5jFJSIGrtLwelWfEJk6vK9ABzMswPB7npHCh00tib6RJHWTS5ZTwyVjM2REFZAL2ajVgxVXcvQCS+GmtRO5PTW9Zi7JRur2egXMOfCzM25tzBVWc1JxkPU2/Yd0Fl3P5JNThCqPrVr12bYsGF8/vnnvsnet99+S7169Tj77LMxGo107drV1/7pp5/m+++/56effmLMmDHlOvbnn39OcXExH3/8McnJ6sT0zTffZMSIEbz44otYLBZycnI477zzaNWqFQAdOnTwbb9r1y7+7//+j/bt2wPQpk2bcvVHEAKp7PPjnnvu8b1u3rw5zzzzDLfddptPDL300kv07NnT9x7g5JNPBiAvL4/XXnuN119/ncsvv5y0tDTatGnD6aefXpaPLsSRFvX0hbd2/q11QXNXkUlTWoL/wyWtGCqLm5wezjBJBIzGUjEaTgzl2526y/fl+NdcKnS4qZWoCpH9AevcAVaaI/kOGqcn6lqGUnTEkNcAEGlczCYjVlPVjxk64cWQwWDg9au6c8rTs3TNfdlFCpNMw3nS+BGnHfwKlEfBaApqJwkUhBMaS5L69LmSUBSF3Lw80lJTMVqSYtr2mmuuYfTo0bz11lvYbDY+++wzrrzySoxGI/n5+TzxxBNMmzaN/fv343K5KCoqYteu8AlUomH9+vV07drVJ4QATjvtNBRFYePGjZx55pmMHDmSoUOHMnjwYAYNGsTll19Ow4YNARg7diw333wzn3zyCYMGDeKyyy7ziSahGhBwjvj9ho0V7LEewzlSmefH77//zvPPP8+GDRvIzc3F5XJRXFxMYWEhSUlJrFy5kssuu0x32/Xr12O3232iTSg/5bELaeOEmtfVF0PaeZLXAgGxFyKtKNIS/cWQdvJ+tNCBonj8BEtZcIYRftpdhxVDAXPVZKvJZxHSUux0UytR33sg0EJ1uEC1GBV6Y4Y0lqFUnZgh79hEch+0VBPL0AkfMwSQnmjBFOYH/rX7LI55kmmk7IMN03TbiJuccEJjMKhuOJX5Z0lS/xtiuzmNGDECj8fDtGnT2L17N//88w/XXHMNAPfffz/ff/89zz33HP/88w8rV66kc+fOOBzxeSoYiQ8//JAFCxbQr18/vvrqK9q2bcvChQsBeOKJJ1i7di3nnnsuf/zxBx07duT777+vlH4JcUDvHPH+hiv6L4ZzpLLOjx07dnDeeefRpUsXvvvuO5YtW8bEiRMBfPtLTEwMuX24dTWdhdsOsyzK+jOxoigefvl3X8ypmrdogvptZv2ppXZupK1PE66mo8fjYdq/+32B/6Eodrr5YcVeDufbg9ZtPJDH7PVZIbfzklYy6T9a4OD7FXvI8SbWQrVqHdO8Lyv7jxXzw4q9zN+SzZIdR3zL1+zNYe7m0qQHemLog3+2MWfjQfLt/sKnYbr+uVDkcLM9u4D3/t7qW1Y7SRVHgfE7ny7chcfj8Y2Hfza50AkUjhQEj3eyZluTRgwdzLPz/Yo9FDncbD2Uz9tztvLzqsp7iBqOE94yBKppsk6ylUN5wV8qQBEJfOIezF3mH3DPex1Tx/OD2rglm5wgVAsSEhK4+OKL+eyzz9iyZQvt2rXjlFNOAdRg7ZEjR3LRRRcBkJ+fz44dO+Jy3A4dOjBlyhQKCgp81qF58+ZhNBpp166dr1337t3p3r0748aNo2/fvnz++eeceuqpALRt25a2bdty7733ctVVV/Hhhx/6+ioI8aCyzo9ly5ahKArjx4/3Wca+/vprvzZdunRh9uzZPPnkk0Hbt2nThsTERGbPns3ll19epj5UR3KLnVz5nvqAZNMzw7CGEB5lwQD8sGof/52qJjTY8cK5UW+7XSNWQll6tM+Ji6MUQ7+tzeLOz5dH7M/Lv21k0tztdGqcxi93neG3buirfwPw85jT6dyklt86reiwlbiGTfxzCx/M3Y7FZAhqWyfZGrIP0eD9LF7WPDmUZKuJ896Y67dcz+LyzDQ1MUXL+v6Wt3opVnZkG4LGvcjp5tEf1rBUI5y98T/eMTcb1e1+X5/F6r05PotdYqRsciWWJT3Rlmg1+yxVFlNpNrnHShJlrOqXQ6/mdXhxxgZ6t6jDiK6VF28cCrEMlVAvxRZyXZPaiXzOOdg9Zkx7l8CuhUFttD/CcCe2IAjHn2uuuYZp06YxefJk31NvUCdYU6dOZeXKlaxatYqrr746KLNWeY6ZkJDADTfcwJo1a/jzzz+56667uO6668jMzGT79u2MGzeOBQsWsHPnTmbOnMnmzZvp0KEDRUVFjBkzhjlz5rBz507mzZvHkiVL/GKKBCFeVMb50bp1a5xOJ2+88Qbbtm3jk08+4Z133vFrM27cOJYsWcIdd9zBv//+y4YNG3j77bfJzs4mISGB//73vzz44IN8+eWXbN26lYULFzJp0qRyffaqTk5hqXXiWFGcLdYGWLD1SOR2OkQjbkK5yYWbM4VKxhDI9yvUBAFr9oZO0+1NWa1FO5n31kHan6vG1wRaT8pTeDUUh/PtHMgtDloeLhZnz5Eiv/eJFhO1dURaocPtE1UNayUAUOxUz1evy9p/BpbGnmbn2ymMMmbI6bMMBfdTaxk0GQ2+mCEv36/Yi93lDmp7PKkavagC1EsJrfab1U3CmJLJVHfJ04b5bwS10QYAesRNThCqNAMGDKBOnTps3LiRq6++2rd8woQJ1K5dm379+jFixAiGDh3qeypeXpKSkvjtt984cuQIvXr14tJLL2XgwIG8+eabvvUbNmzgkksuoW3bttxyyy3ceeed3HrrrZhMJg4fPsz1119P27Ztufzyyxk2bJjuE3NBKC+VcX507dqVCRMm8OKLL9KpUyc+++wznn/+eb82bdu2ZebMmaxatYrevXvTt29ffvzxR8xmdXL26KOPMnbsWJ577jlOPvlkrrjiCg4ePFj2D14NKNSIiHhPzg3E7HXsQyscQqVQ1saMFGuTVYURQ+ESDvi3iyzK9ULztGPozbAWqnaOnktYeckpcvq5GHrJ1nH38+IIiL2xmU3USSqdwzYucZsrdrp9SSAeOEf1PvCKEK8AbZuZSo9mtQE1w593+pqocXXTEyzhLENai5o2tbYXbbIymzk4Bv94IG5yJYSzDCVbzdRNsfJBznCuMv+pxg1lb4F6rX1tpOiqIFQfjEYj+/YF+yo3b96cP/74w2/ZnXfe6fc+FregwAcjnTt3Dtq/l8zMzJAxQFarlS+++CLq4wpCeais8+Pee+/l3nvv9Vt23XXX+b0/66yzmDdvXsh+PvTQQ4wZM4a0tLSKT0RRBdBmEjuSXzmxjNGgDcjXyw6nKB6/eVKRw6VpH3rSFDjxD8Qr3sIlJvBi1FF62sm8tyBqvj2UGCp/zFAghwscuvFQgdnfwmGzGH3ue41qJVAv1cbeY0UUOdw+AZpiU2OFvCLEqXGTs5aIlVxNTJS26KpBZ9y8IlVPDGlj8C0mY7AYMhl9lsQES9U4Z6tGL6oAgZahkf2a8+IlnamVaOHqPidRL8XGVk9j9mb0BzywwN86pE1TKG5ygiAIgiCUBadbYc7Gg+QVB0++tcHz2hovK3YdZWdAMc6F2w6z75i/S1U4QhmFFm07zF7NfjweD39vOsSPK/dSUCIctNYgPUtPoKiJ1k1Om97aoWP98fbZFcIapWj2HTipVxQP3y3fE9SPgpBiSN9as3L3sYgJHkIxdflev5geL7F8bwlmE3VK5rCtMlJILBEYhU6tGFJtHw6Xgsfj8Qk/s8ngizvzJoyw6FhzAjmUb2fOxoO6sU3abU1GA+YAN7m9x4pYukP9zFXFMiRiqISGtUqzcVzcvTFPnH8yV/Q6iZWPDaZ/uwyfWFrU8Fq10covIL/Ul1V78oubnCDUfD777DNSUlJ0/7y1UAThREXOj7Iz8c8tjPxwCTdNWRq0TuvC5X0qvyO7gIvems9ZL8/xrZu/NZsr31vIOSXJA6JCRw0t23mUK95byOAJf/mWrdh9jOsnL+buL1fy9hw1U5krwgNhe4CQ0brJhRNDXrcu0BcpXmtPKFc7rQgL/HgLth3mH00GN6+gCyyz4s3Apjfx332kkAsnzqP//+aE/Azh+HnVPqb9uz9o+YEYLUP1S7yb2mamkmRVhU+xw+37TNr02HaXokmgYPSJoWMl8WjaeKFQvPzbRkZ+uAS96a5W/FiMRp/lScu01ft9fa8KiJtcCT2b1/a91v5ovE8S6pb80P41duDixj1g7zJY/B4MeBiQbHKCcKJx/vnn06dPH911Fot+bQdBOFGQ86PsfLl4NwCLdwQnM9C6yR0ucZP7d29OULufVqpujrkh4l/00LMMzVijTlq1sUoHNQH/B3zJBsLHAAVadfzrDIV2ccstKu1/vt0VlChAz/XN77haMRTQdG+A9cXr3hfoJtegViJHC526SQ02HghOyhAP8kJYp/SwmY1c2fskip1ubujbnBdnbADUbHKOAMsQgN2p+L4vs6nUTc5rGdLGC3n5cGQv/tp0iEN5dp+Q0R5fK3ZNRn/LUDgrU0IVsQyJGCqhY8M032u9zB7emKLDhU7o9x/45gZY8j6cfi9Yk/yzyYllSBBqPKmpqaSmph7vbghClUTOj7ITrlah1mpxtMRNrlin4ObOw7HVCQJVDAUe+kBusGuY1uPN4YtBCW/pCXSTK3ZF5yZ3WOOa5hUpWte3SJVitSLMENBYmwEP1Dgaj8cTJIYa1kpg/f5cXcuQdu53vIqK2swmWtVP4YVLugCl8T6FDrfPHS7RasJoUB/W211u35hbdNzk9CxDZ7fP4Oz2Gdz39aqgdakJZuya+DWLX8xQeDFUVSxDVaMXVQCz5stqnB5crdvrJpedZ4cOI8hLbAJFR2HlZ4B/wKAUXRVOFMQltGYg32PFIONavTle31847xLtRN07OS9yBouhXTEWTQ1FlsZdyzvZ11pyvGLDFSlmKNBNLsqYIW2Avveza4WVMQYxFGiBKgwQkS63QrFTCepPZlpCUF+8hCokW9EEJinQ4i2YWmB3+X5LVpPRJ5LsLsXnPmfSuLEd81mGQttJAmsvQXDqbW3fzCYjFnPoL0lSa1dBfrnrdG7o24wxA1oHrfNZhgrsOBQDL+UOAsA97w1Q3BIzJJxQeN1cCgvjc8MVji/e71Hcl+KDnB81g0jnhcutsHL3Md/T93gR7oGqX8xQydP4QAsH+LuA5RY7WbM3J+LcJHDKeijP7ueq543Z0fbPK0y0Y+ByK2w7lO8X97IjILmDVjgoHjU2SQkQIW7F45ugQ+ln9xdD4dWQn/teiQDIKXSydl+On6seqCJOL5NcgxIxtOVgPhsO5KIoHlbuPuaXuhpKBd7hYvh9fcWmeK8bpvir183tr02lce0Ws9EnPIqdbp8wNBtLLUPLShI5JIax1gQmQ4DgoqxacabNVqdHVUmgIG5yGjo1rkWnxrV019X1WobyHRS73HzjPot7zd9SJ2cnrP8Zt9LM1/Y4WUoFodIwmUykp6f7anokJSXppt+sKBRFweFwUFxcfEKk060o3G43eXl55OXlUbt2bUymqnFjqu5Ec37Ibzg+VMQ4ejweCgsLOXjwIOnp6SHPiyd+XsunC3cx6rTmPD4ifkkhwomhAkewm5yfsFA8QS5pF7w5j+3ZBXx9a196t6gTdT+un7zY731esYv0JGsIN7nSPh/IKWbAeDXhwo4XzkVRPIz6cInfvoqc/n285O35PDy8A6PPbOlbdqzQ4ee2542j8Xd9C/8AWs8yNOy1v9mXU+wbC5PRgFvx4HLriyFvwVK7S+GcV//hxtNaMHneds5uV5+BHTI1n8lNssXAC6tMOFasDNmneFAn2crBPP3sdl4L0GpNLJnFZCgRHk7/BAoaNznvsmSdIqul+wk+x5IDLEnmCHWG/PtaNa59IoaixGsZOlroIL/YRTE2PnEP5m7z9zD/dVxJL/vaRuMml1PkZNG2w/Rvl+H7IQpCdaJBgwYAx6XIocfjoaioiMTExEoVYTUNj8dDQUEBDRs29H2fQnyIdH7Ibzg+VOQ4pqenhz0vPl24C4AP5+2IrxgK4zamjRnyBq37pan2eLAHCI3tJWmf/9x4MLwYChi+9ftz/d57hYI2LEDPMrRNk2ba5VZ03eYCrTIAz/263k8MBbqdFeiIIZfiCcpU5/F4fL8F7TqHW40J2ldisVq8XbV6pSaYOVboxK14dAuuZpaIIS+T520H4M+Nh+jTsq5veaHDTbbixqFE/zu8vm8zsnKL2XO0iLX7/Me7W9N02mSk8M2yPUHbhRMsSToJECxGoy8+x+4qzTKnzSbn5eYzWgZt79uPjrDxTzqmWoO8REqgIJahakbtJKsv+Gx/jmp+/tg1hLts0zHuXUaLRv8CGUB0bnIjP1zMil3HuPWslowb1qEiuy4IFYLBYKBhw4ZkZGTgdMa/GF04nE4nf//9N2eeeaa4dpUDl8vFH3/8Qbdu3WRCHmcinR/yG44PFTWOFovluFlKw00htJYLrwuYVjS4FU/I7GyNAib1gRiAwEMnW03UT7Wx43ChRgyVrteLGdJSYHdj0MyF22amsCkr3y9ltpfAz10cIOp8bnIageN0K0GpsJ1uD9aSOBVHgPue1ppiMRlwuj0+MeR0K+TZg89Vb2ptPbTiqcjpxu6I3jVoZL/mPHG+KqLv+3pVkBiqn2rj5cu66oqhcK5ngQkQzEYDRqPBl7lNGxdlMfm7sbXJSOGstvVD7tusE6SljRkyGgx+9xKL0agbZ+SlqsQMiRiKEpPRQJ1kK9n5DvYcVcXQYWpxtM0l1N3wOQOPfc2bjAGic5NbsesYAN8t2ytiSKjWmEymSp80mEwmXC4XCQkJMpEsB06nU2IcK5hQ54f8huNDTRzHcBlptZNvrxgqDhBDobaPdKYbCE500CojxSdSvMd26yRQCHTN85Jnd/pNzr2v9SxDgQQKpjydBAqKR42JCtzOa+3wsyK5PWw5mO9776vBY7MARWrMkI5lKJz3jlacFjvcFDuifzCoteDoHSNcXFC4PgWKIa9lxt8ypI6LSRMzFNgnPcw6IkwbMxSolbRueHpINrlqSN1k1VVutyZLy74ONwIGuhfOp5VhL1DqJufxeHQrJguCIAiCUPXJt7v86upUBmETKGgm315rjDb+xqV4QmZniyRA7G58LmReWmekkGxTJ8hHCx3sPlLot//cYif7jhWFtQx5RYfFZPBNpkNlXtuclUehw4XTrfgJF4AVu9QA/8B5lbdYqJdDeXay8+1BbXcdKWSNTk0mr5uXS/H4xWR5CWeF0X4fucUuVuw+FrJtIFrRomchqVNGMRT4GbyWGe8xNmXl+1wXLSb/oqgJEQquWnQtQ6UPIQI9DMxGo9QZqmnUS7WyMQufZQggN7kFtBsOG6dxk2k6D7lGo3hUv9QL35pPbpGTn8acRmpCzXhiJQiCIAgnCv1f/pPsfAeLHhroS7Fc0YRLrZ2nYxkq0kx+3eHEUITUz06PgVV7/MVC64wUX+HTsSU1ZoZ0LE0asOdoEf1e+IPmdYNLkoBaJNZrbbCYjD43q1B9GfzK3zROT6R1RopfNjSAfzZnM2PNAeqn2vyWHyv0T3ntTd6w7qmhfmLok4U7dY/pnZ+53ErsliFN+/9+96+vVk80aK0iesfwiiFviEaoPqUl+k/lQ7X1Cp0Xft3gWxdoGdIruKpF1zJkK90mUCpFSqAglqFqiNcy9OWS3b5ldpcbTvsPAJeY5lKPHBSPms1l1e5jbM8u4OMF+iegirioCIIgCEJVJLskffX8rdmVdsxwCRS0E3/v0/0Ce4CbXBktQ3pkpCb4BcgDzFyXFdRuR4gir3nFLp9bm1kTTK9XKNbL3mNFfkIoWTNB35yVF2QZOhQiq1pWrj2k+56WNI1lKE8nm1xqgoV3r+uhu63WMhSLEApEz/rUpLYqML+5rR+ntqxDp8ZpvnU2k5GnL+zEgPYZXNX7JL/tLu/ZxO+9uSTLop71yRKQQCGSm5xeXafAmCH/Yxv8YoZG9mvut76qJFAQMRQDekGJdqcCTfuwydIem8HJDebfUBT/wL/PF+3SDRYUBEEQBKHq47WOVAahYn6KnW4KNCLC65pWECfLkB4pNnNQUc1YyLe7fBYsq9noK8hZHEMIQfuGadx8eoug/Xk5EMKN0Ww0BLXVw+cmF8IylJZgZujJDXjz6u5B6/TEU1nQswy1zkgBoEez2nx5S1+6NEn3a3/dqc2YPLJXkGtbaoKFL0af6nvvLXqq97MyByRQiOQmV6DzeZOs/tnktBgM/pahW89qyT2D2vjeV5UEClWjF9WE3s2DU1Ku25/Lfd/8y/vuEQBcZ5qFwVngF9C491gRH/yzvdL6KQiCIAhC/MgrrryMmaFCho4GuIM5FQWPx782jktR4moZSk0wh03jHIkCuwunqzQ+xWsliKUvNrPRF6SfZ3cFWYaycvUtQ26dtNt6+NzkdIquJltNvjgYvRgePXFQFvRcyZoFuB5q43XCuZ6Bv/uZt622EK+XIDe5CGIoV0csan3j9IrgavtaO8nqZ32KJL4qCxFDMXB5r6bUS/E/Gd74YwvfLd/Dd4Vd2a5kkm4ooPmuqUEn+sy1Byqzq4IgCIIgxEix0+27f2tFRSwWALfiIacwevGkFheN7DK/7ZBav8f7JN/jIag2TrhscnqWoUiuXSk2c5CbXCxo3eQsplLLUCxWqgSLyWedOpxv51hRYMIEfcuQS1GiSmLlE1rFLg4X+AvOJI0Q1BNDgfFKZUXPMhQoeLTxOpHqU2oTE3h/L9p4d+0xYnGTC0xjDv5xQnoVGrwCONlqIsFiipg44nhQNXpRTUiymrlFUxBMi4KRSe7hALTd/glFdv8nFZsP5of1AxYEQRAE4fihKB56Pfs7XZ+aicOl+LlY6U0CQ3HPVyvp9ezvfplnQ7Fi11G6PTWL+75ZFbbd9yv2cM0HiwDISCtNIBBozXArnpCZ3QIf0u46XEjXJ2eGPW5yHNzkXD4xZNANwI+EzWz09eG3tVncHzBWoSxDLiW6jL5pJZah7dkFTPt3v986bbySnhjyxpSVBa1VJJK4AdWlLdr2epYhPeFhNBCTZUivzpBNs03tpOAx8oqxOiXGhESNW50kUKimpIXJCvet+0wOe1JJKdqLbfM0ABrWSsBiMlDocLMvJ1iVS4kPQRAEQTj+FDrdqiXDpZCVW1xmMbR851EcboVt2QUR2749ZysAU5fv1V3vtU498O2/vmXarHZOt+LnCuZWPCFTcwdaYz5asCNi/1ITyimGil2a1NpG3dTMkdC6yemRFSJmyOX2RJVAIZzlS+siWDfZFjbNNqiWkRap4Sd29w1uS49mtbmsR1PfMlvAfj8c2StoO4tRYxmK5CZn1oohdcwnXnMK7Ruk0rVpOnWSrVzV+yQMBoPfsRMiWIbuGdyGTo3TePGSzow5uzV9WtRh6MmZTB7Zkw4N03jn2uBEE12aptP9pHRfoget+KoqCRQktXaMhEuRXYyNT9yDucc8lfqr3wP+S4rNTFqChY1ZeWzOyvdlBxEEQRAEoepQHCAWnBoLSywxQ97YHmc0LloRhIbTrWAymshMS/C5OWVqLEMOl3+MUNg6QwGfLxrLVYqtnDFDjsAECmWxDJnCjtPBENnknO7o3OSiFUMmo4HMWjZ2Hwl+sO3ltcu74Nm1nP9bYg157LsGtuGugW38lmkFwu9jz/IlT9ASi2VIa3XyWuNObVmXGfecGdTWonWTi2AZalgrkV/uOiNo+YD2mQxon6mzhfob+v6O03zvTRpfugSxDFVPIvnOfuwagstoI/Xwv/QxbCDRaqJNpvqj3pSVVxldFARBEAQhRrRuZA63v5vc0ShjgIqdbgpL9hNNJrMkm//k0xWwjXcfjdMTfctqJVp9sRmBWdliSa29WyeGJKh/VlNcY4a0aZajJcFijKoP9VL86w+5o3STC/eQOznAUtIwLTFES5XW9dX5XqwWMK24CWX10cYQRYq18VsfwQNJe7xIdYbigXZoIlm4Kouq0YtqRKQT8ghpbGl0PgCjzb+QYDH5FL43+FGLeMkJgiAIwvFHaznJL/bPWnakQN/6EIg2AD8aF61kTfxEsdMdJG68wkobi5FX7PS5TAUmaggnhvKKXSgagbAnCsuQwWCIW2pti8ngS6AQCzaLiRRb5ML1jdL9i+I6o3CTMxsNYa0TSQGfvUGt8IV3vRngYv2cWlHgTYUdiCWWmCGN+1kot0m9fcUju1ukT27QWIbKEkNWEVSNXlQjwj1B8PJv02vwYGCQaQWt2EPzuskAbD8c2X9YEARBEITKR2s5uWDiPCbM2uR7fyTKQPmjGjHkDJHIQIv2Cf7RQgf2AFe2Ps/NZs/RwiAXN6/L1PDX//FbHs5Nbu+xIlo+NJ12j/7KV0t2RZ0hL1y8TiTUmCGtZahsCRSSbcGT9OYBqacbBgiVaCxDiRZT2D7VTvKf8wWmuwZI17TxCgtzjBYwq1+Mj35/zDHEDGmFUyxiSFszqKxE+tVbQ4i944mIoRhJi+KikJPYjN2ZAwA4N38qzeupYminiCFBEIQKY+LEiTRv3pyEhAT69OnD4sWLQ7Z1Op089dRTtGrVioSEBLp27cqMGTMqsbdCVSNQcHy/ojSpQWGUqaAP+4mhyJYhu6bN4XyHbl2cSXO3+/XtnkFtdLN6QfjU2l48Hvjvd6sj9s1LanktQyV1hqwmI2e1rR+ybceGabrLEywmUgMsQ1f2aupnxaidZOHcLo38sqE5FSWiZSjJZtIdy1GnNadpnUT+ExDbc9PpLWhZMqfz8tQFnWhSO5H/G9rOt8ysExtVO8nCf89pr9sPbX2eUGIoFsuQ1voSKZGxn5tcJdT9Ob11fTo1TuPynk0q/FjRImIoRqKxDCkeDyubXAvAqfmzaGHLBdT0j4UO/ycx0dQWEARBEMLz1VdfMXbsWB5//HGWL19O165dGTp0KAcPHtRt/8gjj/Duu+/yxhtvsG7dOm677TYuuugiVqxYUck9F6oK4QqBemv6RELrTheVGHJqXfH0xZDZaPAld5g8sietM1JDToZdioIrzmU8ypNAId9eGjNkNhk4u30Gl/bQnwRPGdWLM9rUC1oeaBm6+JTGvHBJFz/R0DojhfO7NmL90+fQrWk6UJJNLoJlKMVm1hUuDw5rzz8PDCAj1d/alJ5k5Y/7+9O5cS3fsrPa1Gfufwdw59mtfcv03ORWPDaE2/u30u2HIYo4mljqDGmJZBnSWicTreWXBZHsPlazkV/uOoOXLu1a7mPFCxFDMRJN5gvFAzuTOrNUaYvZ46TW6ik+M+rOw5F9dAVBEITYmDBhAqNHj2bUqFF07NiRd955h6SkJCZPnqzb/pNPPuGhhx5i+PDhtGzZkttvv53hw4czfvz4Su65UFWIVAg0GnFzpKA0hiea4H27q/SYRwsdQRntAExGoy92KNGiChO9CTyAohD3moaRCnGGwz9mqKTejE69HlAn+3rHspmNfkLApuOKps2+5rWguKMoupqSYNF1aYuU8nnfsdLkE7WSgh+SB1qbYgkhCuVip91nLO6GkUR8NC56NZ0yyf2JEyfy8ssvc+DAAbp27cobb7xB7969Q7Y/duwYDz/8MFOnTuXIkSM0a9aMV199leHDh5e548cLg155XWDqHf24YfJiNUDR46HI6eZ917n0tG6CJZNoV6cfiwpVV7kOIUzBgiAIQuw4HA6WLVvGuHHjfMuMRiODBg1iwYIFutvY7XYSEvyf+iYmJjJ37tyQ7e2aYtq5uarF3+l04nRGn3bZi3ebsmwrlBJpHD0eT8j7diD5ReHjgorsDkwhpk3e42fnlk6Six2uoH4F9qdIE7dzMLeIRmnBQsHgUSgq8SqxGD04nU5CGQbsTqeftam8lPX3mWwzUWB3k1/sosih7sNsUPdXKyGE0FBcQfV2AEwG/35496PVDC3qJvnaeDVDscNFsTN8XFSy1YhHCRagkT63nzukpq33deDHaFYnKew+3e7SfnrcLpxK8G/WqInGMaFE/d24FU/4tprP71Hc5b4maT2eyrqvaK6P8bx2xiyGvK4I77zzDn369OHVV19l6NChbNy4kYyMjKD2DoeDwYMHk5GRwbfffkvjxo3ZuXMn6enp8eh/lSDRYuKUk2pzXpdGfLF4F4qiiqFZSg+OJDSlTvFuzkv4nUWc4Xu64+VooZMbpyxh0g09o75gC4IgCKVkZ2fjdrvJzPSvc5GZmcmGDRt0txk6dCgTJkzgzDPPpFWrVsyePZupU6fidutbB55//nmefPLJoOUzZ84kKans9eNmzZpV5m2FUvTG8Zgdxq820S/Tw7CmkQXCkgMGILRF4NcZM0n2MwKUTqGmT58OwMqtRrxON+s2bGB6/npfmzwnvPyviR71PFzQTO3Pjj2l7Z+dvlH3uNu2biUn3wAYWLJwHnuTwF5sQs8h6eUfl7IhJ35P972fK9bposXjAgy4FA8r12wEjBzYv5fp03ez56D+OM+eNYtDB0rHw8uGtf8yPWuVrw97d+9k+vTt5BwtbXtkxzqmH1sLwLEj6vJ7vv6XSOQfzWbOH7ODPl/p5w5F8HevxV5YiPb7SXTnh93n5pzSMfn1119126w+XNpmxbKlFGyJZAFU+5iTkxv22KrhTm07f+5cdiSHbBoVBzTfYeRxDE+462NhYfw8rWIWQ1pXBIB33nmHadOmMXnyZB588MGg9pMnT+bIkSPMnz8fi0W9ijRv3rx8vT7O3NG/FW+VVI2GUn9a79MIxQPFTgUFIyubXMOALS8wLO87nqKvrrnyjw0H2Xwwn7aZqZXSf0EQhBOd1157jdGjR9O+fXsMBgOtWrVi1KhRId3qxo0bx9ixY33vc3Nzadq0KUOGDCEtLXZrv9PpZNasWQwePNh3bxRiJ9w4PvLjWnKde5mxx8Abt54TcV/75+2A7ZtCru8/YCD1U0tr2dy9YKbvtdfT5ZfPV0JJnFrzlm0YPqg0juSl3zaR49jBH/sMvHu72p8fjiyHw9lh+9WqdWv+PrgDUBg6sD9NayfxxpZ5HCoOTsoUSgid0bou/2w5HPY4XiwmAxaTkadGdGB4t0ZBnzUa6qencOyg2r96jU+CvXto2fwkhg/viG3DQb7YujJom3OHn8Pa3zax4OAuv+W9e5zC0JMzWerZwC//7ufpa/uRkWpjV/I2xv++hQZpNm65uJ8vpntq9nI25oQe03M7N2Da6gMAtGrWhGFD2/Hw0j9966/q1YThwzuG/Xz2hvt4/Od1TLyqm1+ck/f3+No1PRn1yUo8HjV+6PVRp9KsTuiHJg6XwrQ353NS3SSGDz9Ft41l3UGmbFoJwBn9TqVHs9ph++j9zpJTUhg+/LSQ7TweD18dXMqxQicjLz613OmuO/Qu4NJ3FzGyXzOGn60fIxWJaK6PXut8PIhJDJXFFeGnn36ib9++3Hnnnfz444/Ur1+fq6++mv/+97+YTPpPYKq6O8K9A1vRvWkaoz9RA22TrSZ13yWmQbvTxdq9xwDY2vA8zj7wIfXys7jM9BcOZxfdfjgcZftslYm4dcQHGcfyI2MYHyrbFaGiqFevHiaTiaysLL/lWVlZNGjQQHeb+vXr88MPP1BcXMzhw4dp1KgRDz74IC1bttRtb7PZsNlsQcstFku5xEx5txdU9MbRo3kyH80Yh8mfoGI0hdyPd/mxotLzRcHg117rveZdHk2SOrvbQ1HJxqmJCVgsFqwRYloC+fimPvR74Q/25xSHbdeyXjKz7zsLxRN7rRwtZpOJFJuZfLuLnGL1Q9osZiwWCxm19EVBos1Ksk6SKmvJdk9f2Jknzu/k69ddg9ox6oxWJATEFFnCjM0H1/ekTorVJ4ZqJVpJsJW6Jl7V+ySev7hzxM93ee9mXNLzpJBj1L1ZXf59fCgmowG34ok4lhYL/H5ff4yG0OEYCZpEFkkJ1qivGx4i//6/vKUvHg8Yy/Gde2nbMJ0Vjw0p1+/HS7jrYzyvmzGJobK4Imzbto0//viDa665hunTp7NlyxbuuOMOnE4njz/+uO421cEdYZPGpOm2FzB9+nR271JNg2/9ta203ZbtrKk1mM75nzLG/D3jV5xGwoF/CRz6f/75h63JsPiQgT35Bi5qrlBVvebErSM+yDiWHxnD+FBZrggVhdVqpUePHsyePZsLL7wQAEVRmD17NmPGjAm7bUJCAo0bN8bpdPLdd99x+eWXV0KPhapIoBt7IK4o6gaFS62tl4BBm0AhFMc0hVUTSxIMWGKsY2MwGKJKhGA1GzEYDMS4+yBMRnxiyFt7yZslrW6IBAoGg0E3tbN21AMn2HoFYcONTZLN5JetLTCbnC2GLG2RJvve9dGKgkjt/OoMxdDPaJIWGwyGuM454yGEKpPyV1eKgKIoZGRk8N5772EymejRowd79+7l5ZdfDimGqoM7QoNdx5i4Tq1h0bB+HYYP78Xy6Rv4+4C/ebdn9y6073w2R//3K43ch0nc+w/PZA8H/J+2nn7GGbRvkMrdj6pmzasGnsLA9sExWMcTceuIDzKO5UfGMD5UtitCRTJ27FhuuOEGevbsSe/evXn11VcpKCjwuXRff/31NG7cmOeffx6ARYsWsXfvXrp168bevXt54oknUBSFBx544Hh+DOE4opfJTYtTiSabXKxiKJp9lnrKeMVCWVyZEqMQQ6HqF8WKyWBQi7Xmlo6JN1NZ7RBiSO1j8LQ01ux44SbiNrPJT/CkJJgDsrRV3Um8NstcpKKrWiLVnRJiFENlcUVo2LAhFovFzyWuQ4cOHDhwAIfDgdUafFJUB3eE+mmJvteN0hOxWCyYddz+UhJsWBJTmVn3Gq44+DpjzD/wTeFZgP/nNgSY348WuavsJE/cOuKDjGP5kTGMD5XlilCRXHHFFRw6dIjHHnuMAwcO0K1bN2bMmOHzZNi1axdGzZPV4uJiHnnkEbZt20ZKSgrDhw/nk08+qVHJfYTo+XHlXqbM3xG2TSTLkMutkKNxkwsWQ8HbRxJgUComrGajb6JfFtGSZIk85QuV1jlWjEaDL57aa9nyiqFwRVz1LEOxZgoPlx7aZjb6WVVSbGY/17CqnFraWkF1hoQY6wxpXRG8eF0R+vbtq7vNaaedxpYtW1A0T1Q2bdpEw4YNdYVQdaFl/RQmXN6Vh4d34NHz1EA7vacR+Xb1IrCo1nns89ShgeEoV5r+DGoXzRMkQRAEITRjxoxh586d2O12Fi1aRJ8+fXzr5syZw5QpU3zvzzrrLNatW0dxcTHZ2dl8/PHHNGrU6Dj0WqgK3P3lyohtIt2XjxU5/VySHC7/Sah2e2/6YT3LUNvMFL/3RwpVMaQVCtFM2r2i464BahKHhHJYhp664OSgZU3rqA+FW9YPTj9mMhh8x/f232JW920wGOjWNJ1Um9kvIQVAp8ZpQZaa03UKsYYjnGUowRIshrRUZTEUa9HVewa1AeCpCzpVWJ9qCjF/62PHjuX999/no48+Yv369dx+++1BrgjaBAu33347R44c4e6772bTpk1MmzaN5557jjvvvDN+n+I4cfEpTRh9Zkvqpagns56/Zav6JRc1s42JrgsBuMP8Izb86xkEPjGKplibIAiCIAiVQyQxpHWR02uvtSx57/mBNYGa1E5k2n/O8N9vvrpfbcxPNBacM9rWY+2TQ7lvSDsAEqMoGh8qeP/6vs1Z++RQ33wH4P4h7Vj75FAGdcgMam80GnxCwzuf0Vo2vru9H4sfHhQUx9SlSTrLHhnMkocHse254fz7+FBqJcZmnQ7n6mYz+8cMBR6/KrvJaXtmC5GATMs9g9qy9smhnN2uaoVcVEVijhmK1RWhadOm/Pbbb9x777106dKFxo0bc/fdd/Pf//43fp+iimDUXETO79qIi7o39qU+NBoNfO3uz+3mn2hiyOYa02wmu4f52kdjThcEQRAEIf54s36FwxVhfSQxpH1f7HJjNRspDkigUDfFFmSdKChJ7KC1DBmjiHY3GY0+VzUgqgx04faabDNj1YgFo0F1hdNLOmA0qPE4WrSfy2Q0kGg16bpw1UoqFT/RxDkFok00EIgtwDJkswSKoaprGdKOldfKFonkMC6JQillGqUxY8aEzNAzZ86coGV9+/Zl4cKFZTlUtcKkuTi1rJ/M2ZoECCaDASdm3nRdyAuWD7jd/BOfuwdQjPqUxSFucoIgCIJwXGhWN4lth4Lr9mgpr2VI6xJndyqQEGwZStKJmfGSoFkXSbgBQRnhopk+RwpF0goJrztbgk6fjQZDkAuanjWrIsJZIiVQ0AqewEQEVVsMlb6OJYGCEBkZzTiiPf8C/Tm9AXrfus9kt1Kf+oYcrjH97lvvdIkYEgRBEISKwBNh1p2RGpy0KZBwCRTGfL6cewLijhwB7fPtLt9ru8uNx+MJSq0dzuCjdemKSgyFsZCEIpSbnBft3MY7r9GzDJmMwWJIT2hUhBgK7yZnDJuIoCq7yWl/w+UtjCr4I6MZR7QXkUDV7n2C4sLMG+4LAbjd/DOJqAXQgmKGRAwJgiAIQlyI5OIWRdZsXGEa/fLvft992ysCAh9yFmjEULFTwaV4QmZKu/XM4OK/SRpxEZ0YitgkiEhSQM8yNPRkNZuwNvGD0WCgYyP/UiiVZc0IFIH3DW7re20zG/3imdo1SAVKk0AM0Il/qip4+6qXcU8oH+JMGEe0ptnApw3adVPdZ3Cn6UeaGQ9ynWkW77lH4HQrfqrf6ZKYIUEQBEGIB063EtYFyit0TjkpneW7joXYR3T35Yw0G/mHXEEeHoGWoXBptR8c1p6BHTK5/N0FvmXaYqXR1I6pEMuQKdgy1LROEsseGURKgpl2j8woObaB4Z0bclXvpnyxeDegbxmqiLTPWuvO7f1bMWZAa67v1xyz0eD7fIsfHojT5fGJol/vPoP8Yhd1UyJbCI8XqQkWVj02JKa02kJ0yIjGET83uYCTXhvsqFqHLgLgVvMvJFGMw634PSESNzlBEARBiA+RHjB6LUeZaQmh9xHlfTkzVd2HM8B6k1+sFUNK2IKrBoOB5vWS/JbV0YihaAqRlskyVIaYIVATP9jMwQketJnm9FzQKkIMaRMonFQnCYPBQK1Ei18ygSSr2S9Rg81sqtJCyEutJEuZkkoI4RExFEf83OSCLEP+bb93n852JZO6hjxuMM3E6Vb8zN4ihgRBEASh7Gj1QiTXc6/VJ1yWtkhFV700qFUihlz+dYXyHRox5CwVQ6Ge9Ae6Q9WJ0TIULqtaKCInUCjtkynMWHnnPG0yUjXLKieBgjZRQ1VOiCBUHeRXEkfCuckZAy4Cbky87roYgFvMv+ApzvN7QhLqwq0oHg7mFcery4IgCIJQI3Fp7qOfLNzJnZ8t90tY4PF4GDd1Na/P3oy7xE0unGUk2oeUGWmqhWHd/lwmz93OrHVZXP3+Ir+Jf7HLjb3ETU4vAQGEF0PRWIaiSb8diCFC1JA1ID12KLzrGtdO9C07kBs8d6mIgABzmLmYIOghv5I4or0uBD6N0Kvq/JPSj61KQ2ob8mm384sAy5D+JeKer1bS+9nZ/LXpUHw6LQiCIAg1EO199PXZm5m2ej9fL93jW7Z811G+WLyLCbM2+QqDntm2PhBcjBP8kzCEy07XQONq99Qv6xj98VIWbDvs18buVHypuNMSLJzRph4A1/dt5mtjNhn9MrLFahkKNIpc1rNJUJvUwDo0EfSTVrjpiaGuTWqpx+rR1NemYYmlrE+LukHtI2X5Kwt+D6bFMiREgfxK4ogxnJuczhMa1Tqkxg513vUx7qIc37rALDReflq1D4C3/txS7v4KgiAIQk1Fz8PicL7d93r3kSLNclWYtKqfwl//15+FDw0M2lZraQpnmGkQJu7Ii93lZsvBfPWYGSl8cENPZt57pi8zmxdvljMISKAQhZEqMIHCGW3q8/vYM2lZr3SfV/U5id/uOdP3PpY6Q3pi6Ktb+/L72DP96izOvPdM/rjvLFpnpAS1r5jU2pqiqmIZEqJAfiVxRCuGbIEJFEJcYX5W+rFFaUSCKxfL0vd8yyOZ4yXXnCAIgiCERu8+qo372XG4tMhqXkmmN4vJQLO6yaQlWIK21VqawqW2zohKDCk+MdS6fgo2s4m2malB2dxa1y8VELXjkEChdUaqX+IAq8noS9kMkd3ktEkQ9MRQgsVEa02cEKhZ0FrWDxZCUEFuciZxkxNiQ34lcSRc0dVQgYYKRl4riR2yLXmbNNSLc8Q6Q6KGBEEQBCEkegkPnJpaQV4xoiVc0gFtnaFwWdBqJUauWmJ3utnsFUM6FhMvzeqGsAyVI7W21loS6NIfi2WoLDFJgVRMNjkRQ0JsyK8kjmitP4EXGFOYqsbTlFM5lNgCoz2HG82/AoRNuQngETUkCIIgnECs25fLPV+uYPeRQgodLu7/ZhVzNh1iebaBx35a5+fGBvoPFQ/l2hn79UoWbTusL4bC3Kudbg/TV+9n3NR/w9YIiiaDmdYy1CYztBiqm1IqgLTWqqgsQyHEijYFtsXs3yZynaHSbcONVbRUSDY5jQgMihlSFCjIhqy1sPVP2Lcy/h0Qqh1SdDWOxBoz5EXByOzMG7lyx6PcaPqVya5zsDtrhT1WFNdBQRAEQagxjP54KXuPFfHvnhwGtM/g22V7+HbZHsAE7KFPy3pc2L2xr72em9zUFXvV/8v36iZJ0FoVmtVNYufhQmonWTha6MTpVrjjs+UA1A9Rk6Z+qi0qMXS00MHeY2rMUusQLmQAp7VWEyuYjAa/B65X9T6JZ6evD3uMUGJF+7kDxUIsdYbCzWui5YZ+zXl99mYGaGKMYsbjgeJjkH8Q8g/SbP8GbjStop4hh2b/fA/KUd86Cg6BJ0DI9rkNhjwLphNgSuzxQN4BOLodjmyD3P3ql240a/5M/u9NluBl2ve1mkD6Scf7k5WLE+CbrzzCiqEItudxG1rQ1dqUDsbd3GT+lenOGyukj4IgCIJQHfGKh23ZBaTuOBK0/nBJdjYvkWJvCx3B1h2tVeGnMaezKSuPX1bt46MFO/3c7lbsPha07ZW9mvJ/Q9tF5cK2bl8uoLq+aWOBAmlRL5lf7jo9qM2Np7egc5NaXPnewpDbhnJj0+4rULhFkjeREijEyn8GtKZfq7p0bZJeulBRVHFTeFj9K8iGwuyS14c1r7NL/g6Cu/S77wn09BrRNoU4cFJdSKoH2Rth0TtwaCNc9iEk1i73ZzruKG7I2aOKnSPbSoRPyd/R7eAsjO/xTh8Lgx6P7z4rGRFDccQvZijIDzf8RcODkddcl/CO9VVuNM1glvPi8O01F9uF2w7z16ZD3DuorfjHCoIgCDWS+qk2DuWp2eC8wkhLoCHE6YrdhUJrTamVaKFX8zr8tuaAuj9NzJDe8c9sW5+6KTaOFTqC1nlJspoodLhZWyKGwsULeenUONhTxGQ0cGrL4FTVWvRKegDUSSoVQ4HWo0hucpFSa0fE7VQn5dmbIHsT5pw9nFp4GP72ip4SARRovYmGhFqQkskRQzrzDhg55Enn4jO6k57RBJIzICUDUjIhuZ5q7QBY/zNMvRW2/QnvD4SrvoT6bWM/dmXicqiCsOCQauU5sl0jerbB0Z2gOENvbzCqlpzaLVSrjsGgCijFpf65nf7vFVfJe2fA+5LXyfUr77NXECKG4ojWhB2YzjEa39rflJ6sU5rR0biTS4q/B84P2VZ7iX9pxgaW7zrGaa3qcXpJrYJoOVryJC3ckylBEARBON40q5PkE0PZ+cGCwxTwEDLaIqla9ASEuWS/Dk0s796jwWLIWxMonJtcnWQrhY4iDpZ8jmjEUFkJlcW2ThjLUMQEClEWXaXwCBze4hM9ZG9W/x/doU6go8GWVmLBqasKmKR6kFy31KrjXZaSoU7ILWoWvxXrs7jro6UAnNt3IITL7tdhBNzUAr64Co5shQ8GwaWToc2g6PoYD7yWsIJDmr/s0O+LcyLuEpMVajeHOi3Vv9otSl63gFpNwSxzPi0ihuKI1loTfIGJLIY8GHnVdTHvWV/hcmW6ag5O1n/yo3jg19X7adsgldxi9cJS6IjyAlOC3eWm+9OzANjy7DDfBV8QBEEQqhqpCeGnLK/O2kSjWgkM7JAJRJGVVQe9+6A3nXROUenTdr0kRykJkcVQ4IPSeIkhgyE4GUEoy5A2KUNQzFAERzk/NzkU1RKRvblU7Hj/F2aH3oklGeq1gXptoXYzVcgEip6kOmDWj8uKhF/IQjTzmgadYPQf8PV1sGsBfH4ZDH4a+t4ZOYiqrOQfhL9egvU/qUInVkuYwaSOW0r9EqHTwl/0pDVS43qEqBAxFEe0NQhijRnyMlPpyRqlOZ2MO2D+6zD4Sd12q3Yf4/aSQM6mdRKB8HUP9DhaUHphL7C7qZUkYkgQBEGomkQSN4cLHNz00VJ2vHAuUEbLkI4XhzeO6FhhGNcjINVnGQp9v+/doi5bD5XWN2oTUJOnrJiNBr85CIS2DNVOChMzFEUChYYc5krzH2R8cC8UZIVunNYE6rVWRU+9tqoAqttGnahXlMjAP1131KEDKfXh+p9g2lhY8QnMfBgOroPzXimzKNPFUQALJsK818ARkM0wsXaJMCyxeiXXL/nTvi55n5AOYdLAC7EhYiiOaMVILNnk/DHwiusSJlnH41n8PoZ+d6k//DAUO9ULvitGMSTpuQVBEITqgiNCyYlAAsWBHnWTrX6JF/Td5NRlRwpCxwJBqWXIYDDwy12n89Oqfbz39zbf+neuPYUEi4kvFu/yLYuXZUi1hvh/3lDzDn83ucCYoRAHUBTY+gdnLXuTy21zMBk8UACYE6Bu61JLT902JaKnNdgqzgUwHNqpUExx1GYrnP8GZJ4Mvz0EKz9TXf2u+FR1xSsPbpe6vz+fg3w1Bo1Gp8CAhyGzk2oVM1nC70OoMEQMxRGtGAm8oIZ6QqPHbOUUVikt6ercpj49GPJ02Pb2knoH2oJwgiAIglCTiFYMeTweDAZDVJahhukJAWIoePLsdbXSusnpkWwrnVJ1alyLwwUOPzHUv10G2fl23/sEi5HMtPhYHfS8T0ImUAibTS5gm4JsWPEpLPsQju6gkdqIBe6OdLnwHpK7XlTl4k/cYeZiETEY4NTbVWH3zSjYvQjeOxuu+gIadom9Mx4PbPoNfn8cDm1Ql6U3U7OvnXxxhVrIhOgRG1sc0RZ8C8zIEtsJqVqHAFj8vupbGobikhuEXrXtcGj9i8VKJAiCIFRlHFHe47zxPFGJoVqJfu/DWYaOhskSB5Bs9X++nGjxj9mwmow00hzPajJGzN4WFo8HrzVIzwoUTQKFwOKxRkPJfncugO9uhgkd1In80R1gq8W2Vtcx0P4yVzkfQTn54ionhMA/frvM49t6IIyerVq4cvfA5KGw7sfY9rF3OXw0Ar64QhVCibXhnBdgzBLodIkIoSqEWIbiSDg3tVgsQwBzlG4UZXQn8eAK1To09NmQbb1Py2KNGdJSnm0FQRAEoaJxuKILMl+0/Qh/rM/yuZCHo1Gt0kxjRoP+vdqbVCFSzFCgdUYrhiwmQ8zzgCAKDsPepbB7MexZDHuXs9bmZKunEbsNTVhnasgWTyO2ehqx09Mg5EPYBE2/8opLEy+lUMjpx36At+9U42W8NOoOPW+CThezfkMuW9cu1/28VYVo6jxFRb02cPPv8O2NsPUP+Pp66P8QnPVAWCGTZD+E6fvRsO57dYHJplqbTr8XEtPj0zchrogYiiPhBEXslZoN7Oz8H9rPHgVLPoB+d0Fqg7BbxBozpA0yFC0kCIIgVGUcft4XwdnTvDw0dbVuHSA9GtcutdToucgBWMo46U+0looObVaz7iels2LXMS7r2TT0xm4XHFpfInyWqP+PbA1qlmyALobtdGE752pCTlweI8WzT4INJ6t1c+q1hXrt1Al+QpqvXfN6ybD/X54zf8AFpnkkZ5W48ZkTofMlqghqfIqvvcmYp3ldNcVQi3rJ8dtZYm24+huY9SgsfAvmPKcKxQvfAmvAcQqPYJzzIgPXv4/R4wYM0PVKOPthSA/zXQvHHRFDccQVxiRflqzVe+r0o32T3uoToLmvwrAXynx8PbQ3EiVeT1IEQRAEoQLwekE8fcHJZKQl8Oy09ew6UhjULlohBNC+QakwCFUPsKxlJ/zEkCaQ/91rezBrfRYXdW9c2rjgsCp69ixWhc/e5eAsIIi6baBpb2jSC5r0Yleuiz2bVtLKsJe5C+fT2rCPVoZ9pBiKScnfARt3wMZp/vtIbciaVq04ZG1Ki9mvwJ4lXF0yG1TqtsHY62boeoUqBALHQiOAYn/IWzmc3KgWb19zip/QLRcmM5zzPGR0gF/Gwrof1JTiV32hFi11FsPid+Hv8Zjsag0gpUV/jEOeLluckVDpiBiKI+EsM6YypEDMtbvg7HHwyUWwdBL0uqnMx9dDa8kSMSQIgiBUZbxi6NSWdWmTmcqEmZvKvc/2DSOntg6XKjscWjc5rRUlIy2Ba9oo8O8nsGuhKoCObAvegTUVmvSAJr1VAdS4h1p/R8NJDeCktt0odrq5758ZJUs9NOAI489O5LT0I3BoY2nx0/wsyNtPSt5+fLnejGaUducy39mRPpePxWgNHQek/RxV1TIEMKxzw/jv9JTrVTH61bVw4F81sULfO1XvnZzdAHgyTmZB6nB6XflfjBbJDlddEDEUR8KLodj3l1vkhO5nQ+vBsGUWTLsPuAVCFEWLNe5H61crMUOCIAhCVcYrhrwZ0BKs5S8qmZZQOmENdQ8PzLhWL8XmlxUOShIPBJCk6V+iOx/W/wxb/1TjT45uD96gXjto2qvE6tMb6reLunBmgl+yBgMHqEtW/a5wShP/hkXHSgqjlgikpLrQ5UrcCXU4PH16xKB+rQAqV/KH6kqzvnDLn/DFVZC1Rk0uAZDWGAY8gqvDxRya8dvx7aMQMyKG4shJdZJCrjOW4aKRV+xSL0zDX4a3ToXtfzHC2JmflX667WOOGdK0F8OQIAiCUJXxxgx5Xc6SLOUXQ9pYnlAPBQMTETSrmxQkhgIzx+F2Ytu3lHvM33KGcTVdPVvhK40ru9EMTftA89NLrT46bmnlQffjJKargqtpL//lzvDJIbxUZWtQpZF+Etz4G/z8H9j2l2odOvV2sCRGPY5C1ULEUBy5oldTsnKLOa11cJHUslxAcotLTqo6LeCM++DPZ3nU8ilz7N3II1h4xZpaWyxDgiAIQnXA4/H4iqh6xVBiOS1D/VrV9cvwFuo+GGgZalo7kWU7j/otS7QY4fBW1eqz9U/Y8Q8Gey73aGdZ9dpCy7Oh1QBofhrYIrvoxULv5nVYvOOI731FuL830GTfO6GxpcClk493L4Q4IWIojlhMRu4b0k53nV6gYY9mtXlixMmMeHOu7jbalJecdjf8+xUZh7cw1vwNT7puCGrvjrHoqsQMCYIgCNUBbSY5nxgKYxkyGOClS7rww8q9zNtyOGj9XQNaM+q0FlEdW5v8AKBhuhqYn0YBpxnXcIZxNf2VNfBGQE3AxDr8nN+Wv5UuLDV25c8x10Z1vLLyznU9+GLxLl7+baO6oAJu663qpzD+sq7US41PsVhBqAqIGKok9CxDO7ILwgZv+ixDAGYbDP8ffHIh15tm8q37TNZ6/C/kzpjd5DSvRQwJgiAIVRRvvBCUuraF87hItpq5rGdTil2Krhi6d1DbqOv+BFqGGqQl0Mawh6+tT1HbkK8u9ABGC5x0KrQqsf406MpdD/2q9rkSatzXSbZy59mtfWKoou7rl/RoErmRIFQjRAxVEnoX7cMFjqCLrBY/yxDgadmfn919Od+0gGctk7nY8SQKkf2dQ+HvJhfTpoIgCIJQaeiJoazc4pDtU2zq9CZUXFEsBVADLUO1bAqvWiZS25DPbqU+M5We7K3Th8fG3BJce6aEuBUCjQHxfheE6Kj4RxUCoH/hbZOhJrYMlVsht8g/EM+teHjaeS25nkS6GbdylekPv/UxxwyJm5wgCIJQDfC6yVlMBt/9NFw9oZQEVQyVN64I/JMsAHTa9A4nG3dyxJPCxY4neNp1HetSTg0phOD4xOXKfV0QokPEUCWhjRkadVpz7jy7Fe9e1wMI9nv2Ng20DLkUD4eozXjX5QA8YP6SuuRo1sdadFUSKAiCIAhVH69lSCtMOjWqBYDFGHz/8lqGwsUVRYvWMtTDsJFWm94H4CHnzRxCzQDXtUl6uY8TbxpKsgNBiApxk6sktG5ydZOtjBnQxvc+wWKi0OH2vU9LsJBT5PRbBqVPeT51D+Iy0190Mu7gIcvn3Oe8HShf0VV5gCQIgiBUVXw1hjTC5KkLTqZxuo2GBVtJat6FeduOMu3f/YBGDGksQ/3b1eeUk2rTuXGtmI5tKzlmMkVMsLyNwaPwnfsMZii9Abi9fyv+o7mnH28+HNWLNXtyGNA+43h3RRCqBWIZqiS0YijQZS4hwB85tcS8X+Dwtwx5xYsbEw87b0TxGLjE9A99DOvV5eVJrS1qSBAEQaii2HUsQxlpCTx4TjvqJ8JlPZrwyLkdfOtsOhnnLCYj/xnYhrNjFAley9DD5k9pZjyIPbkRz3lG+db/95z2cXHHixdnt8vgroFtTsyiqIJQBkQMVRJaMRRYwC0hwIyfWlIRu9DhDunKtsrTms/dAwB42jIZCy6cMbrJSTY5QRAEoTrgDCi4qkeDtFK3MG9RVK1IsZjKJg6sJiMDjcu42vwnisfAjjPGY0qMzbokCELVRcRQJWHUPKExBjytCby4ey1DbsXjexrmfa/lJdcVZHvSaGvcy02m6eXKJqdIzJAgCIJQyWw8kMd3y/aEzAy371gRy3YeKY0ZCiOGtJaQAyX701qGzMayTXmsjiO8YFHjhD5wD8fZ9DTSkyxl2pcgCFUPEUOVRCyWobSE0lCuAnupq1ygK1suKTznvBqA/5i/J82+P6Y+KX7Z5GLaVBAEQRDKhd3l5tzX/+G+b1Zxx2fLddvc8slSLnl7AZsPqvV8AjO7BZJUYglqXZKtVWsZCrz3RoXHQ+KMsdQ35LJBacp412VYzcaoEyY0LinQelKdpNiPLQhCpSAJFCoJ7UU4sOZQgsUY0NZIosVEkdNNocNN3ZLlepafqcoZXKHMoY9xA5dkvQEMj7pP2v1JNjlBEAShMim0u32Jf3YdKQxaX+x0s25fLgDbDhUApbFAofjhztN4/+9t/GegmtAgSSOGyhQbu/IzjBun4fCYGOu8HTtWrCYjj5zXEZPRwMWnhC9A+unNfXh7zhZu79869mMLglApiGWokjD6iSH/Yb+8Z1O/9yajgWSbegH/dNFOip1qVjl9wWLgEeeNOD0muhXOh42/Rt0n7Y3BIzFDgiAIQiWizYBaFJA9FWDH4QKf18LRQgcQ3k0OoG1mKi9f1pWmJZaYBHOpGHLGWl386A749UEAXlMuZ52nOaBmtKuVaOGFS7rQu0WdsLtoUS+Zly7tSot6oWsQCYJwfBExVElo6wwFWvkv6t6YN6/urllvIMmqGu3e/Wsb42duBPwTHmjZ7GnCB+4Si9D0B8AR/IRND62bnGSTEwRBECoTbW28AocrKHZ1c1a+7/XhAlUMWSK4yQWifRDpDJFxVdd7TnHD97eDIw9O6ssnxgt8qyK56gmCUL2QM7qS0BqDAi1DBoOBU1vW1aw3+Jn2f16lxgKFK6r6uusisk0ZkLML/n45qj75JVAQLSQIgiBUIi631jsBCp3+1qEtB0vF0JECNTtcJMtQ+OPp30N1EysseBN2zQdrClz4Nh5DaZvy9EEQhKqHnNGVhPZiq/cUKjCw01swDkp9nsOlvy4igQ/T1OKrzH8DDm2M2CetAJJscoIgCEJlElgoPL/Yv7belkMaMZRf4iZXDqtMKMtQy/oBLmwHVsPsp9XX57wAdVr4rY4UtyQIQvVCzuhKwhSh+Jk2qYLH4yFJI4a82eYiuTsvtp0KbYeB4oRp96mP2sKgSAIFQRAE4TgRaKnJtzv93m/RuMlll4ih8hQ3DeVd8e51PRjSMZPv7+gHLjtMvVW9j7YbDt2vDWovbnKCULOQM7qS0Frh9XSR1nLkARI0T568lqFIgsXp9sCwF8GcCDv+gX+/Dtve7ZdaW8SQIAiCUHkEWYbspW5yLrfC9uwC33tHiXBKtJRDDIWwDDWrm8x71/ek+0m14Y9n4OBaSKoHI1733bC1t21jWVJ0C4JQZRExVEkEptMOt97jwa/Yqq0k9XYkMeRWPFC7GZz1f+qCmQ9D0dHQ7T0ihgRBEITjQ6A40brJ7T5a5BNAWgLr8sVCxGxyO+aqbuYA578BKfXLfCxBEKoPZRJDEydOpHnz5iQkJNCnTx8WL14csu2UKVMwGAx+fwkJCWXucHUlkhjSxgwpHo9fmtHCkteRMr75nrL1vQvqtYWCQ+pTrhBI0VVBEAShrBzIKcbuCk6JHYl9x4pwuZUgtzWtm5w2eYKWpHK4yYWKGQKgOFfNHocHul8H7aOv2ScIQvUmZjH01VdfMXbsWB5//HGWL19O165dGTp0KAcPHgy5TVpaGvv37/f97dy5s1ydro5EihnSmt09QL699AlZQcnryJahkhuL2QrnjldfL5kEe5fpt/dIzJAgCIIQO5uz8jj1+dlcOHF+TNvN35pNvxf+4KaPlga5yeVpLENbS5InBCYrKI+bXJ1ka+iVMx5Us7GmN4Nzni/zMQRBqH7ELIYmTJjA6NGjGTVqFB07duSdd94hKSmJyZMnh9zGYDDQoEED319mZma5Ol0d0VqGDETwN/ZAoaP0puB1HYgkWDZl5bNkxxH1TYszocsV6s5+GavWTAhAkZghQRAEoQz8/K9a8mH9/tyYtps8dzsAf206FOS2pn0I6L3vNazl70lSlgQKk0f2pHeLOjx3UWf9But/hpWfAQa46F2wpQY1kTukINRcYhJDDoeDZcuWMWjQoNIdGI0MGjSIBQsWhNwuPz+fZs2a0bRpUy644ALWrl1b9h5XUwwRLENaPHi4vm9z3/u8KC1DAJe9o/kehjwDtlqwfyX8+SzsXAAH1sCxXVB0FMVdeuMRMSQIgiBEi9VUtiQC2njYwHtagUYMea1GtRItfm3KIoYGtM/k61v7clLdpOCVeVnw893q69PvgWZ9Y96/IAjVG3PkJqVkZ2fjdruDLDuZmZls2LBBd5t27doxefJkunTpQk5ODv/73//o168fa9eupUmTJrrb2O127Ha7731urvrkyel04nQ6dbcJh3ebsmxbEbjc7rB9cbsVru7VmLpJZu7++l8K7C4cDgeOKPvv27etNsb+D2P67QH4Z7z6p+EG4FKbjXwSSfy9NsqS2uoTMVsaWFPxJKSCNRVsqXia9MaZ2c1//0KZqGq/x+qIjGF8iGYcZYwFPSxlTC9d7NRmjAtwk7MHP6BLCxRD5XCTC8LjgZ/ugsLDkNkZ+j8Uv30LglBtiEkMlYW+ffvSt2/pk5Z+/frRoUMH3n33XZ5++mndbZ5//nmefPLJoOUzZ84kKUnnyU6UzJo1q8zbxgd1uFetXIll74qQ6/cfOMBvM/ahZhk1o3jgh19+ZVueAYh8I5g+fbrv9drDmVyYPpBG9q2YlSLM7mIs7kJMHnWCk2ywk4wdCo5BwfaQ+1QMJuZ2eAls9avAONYMZBzLj4xhfAg3joWFhZXYE6G6YNaIIbvLjc0cnUgpdpZaho4WOvzW5Re7cLgU3IrHJ5TSk/zjfMqTQCGIZVNg829gssLF76nxtoIgnHDEJIbq1auHyWQiKyvLb3lWVhYNGjSIah8Wi4Xu3buzZcuWkG3GjRvH2LFjfe9zc3Np2rQpQ4YMIS0tLZYuA+qTzVmzZjF48GAsFkvkDSqIuxfMBKBbt24M79ow5PrMzAYMH94Nj8fDf5fMwuOB0/oPpPb+XFivJ6L8GTZsGAaDgXlbD/PelGW8x01sfnqIb70CKG4Hn/y9lg//XEMaRdx7Rgb9myWAPReDPR/sueDIg+JcjDv/wXh4C2dbVzGdQcd9HKs7VeX3WJ2RMYwP0Yyj1zJfHZg4cSIvv/wyBw4coGvXrrzxxhv07t07ZPtXX32Vt99+m127dlGvXj0uvfRSnn/++RMy42msaDOgFtijF0Pa7HNjv17lty6v2MVl7y5g04E8hndW75G1Ev2nKeVJre3H3mXw28Pq64GPQ2bH+OxXEIRqR0xiyGq10qNHD2bPns2FF14IgKIozJ49mzFjxkS1D7fbzerVqxk+PHTaSpvNhs1mC1pusVjKNfEp7/bxwmw2he+HweBbn2I1k2d3YXeDwRDdTcBoMmM2GVm+u3QSE3Q8i4Viax12e1SXx4N1O2M++ST9He6YB1OGY179JQntT6ky41jdkXEsPzKG8SHcOFaX8fVmOn3nnXfo06cPr776KkOHDmXjxo1kZGQEtf/888958MEHmTx5Mv369WPTpk2MHDkSg8HAhAkTjsMnqF5okx/kF7vCZ2rToLUMBbL7aCGrdh8D4I8N6kPX9EQrBoPq0QZxcpPb/g98cSU4C6DFWXDqHRE3kTKrglBzidnpd+zYsbz//vt89NFHrF+/nttvv52CggJGjRoFwPXXX8+4ceN87Z966ilmzpzJtm3bWL58Oddeey07d+7k5ptvjt+nqGFocxmkJKh6Nd/uCkpDGgpvu0gF5qLOJtf8NGh2Oga3gzYHp0XVB0EQhMok1kyn8+fP57TTTuPqq6+mefPmDBkyhKuuuips3TyhFG0ihDx79HFlenWJMlLVh59bskprCx0tVPdpNRtJ18QNJVnL6d2/cQZ8egk48tWsq1d+BkapPy8IJzIxX1WuuOIKDh06xGOPPcaBAwfo1q0bM2bM8CVV2LVrF0bNheXo0aOMHj2aAwcOULt2bXr06MH8+fPp2PHENUlHzixXKkxSbCViqNgVdcY3h1shwWLC6QovhrRaKeK+z/o/+HguzbLnoOQdgDpNo+qLIAhCRePNdKp9EBcp02m/fv349NNPWbx4Mb1792bbtm1Mnz6d6667Trd9TU/sEyuFGgGUU2CP+nNoEyh4aV0/mex8u18CBR8ehdpJVp84MhsUv2PFMo6GtVMx/XQHBsWF0mYo7osngTEBYvwOqut3Fo7q/nusKsg4xofKTu5TpkcsY8aMCekWN2fOHL/3r7zyCq+88kpZDlPjuKJnU5buPMKQjuHrLGl1iTdYtNDhjrowqjfwNJJlKKaiqy3OQmnSG9OexbBoIgx7Iaq+CIIgVDRlyXR69dVXk52dzemnn47H48HlcnHbbbfx0EP6GcVqbmKf2HArYDLC+p1GvM4lc+Yt5NC6SEXB1e0K7SYCnc7yjmZT12bgUHHwg8ItmzaC3ejbZuG8v9kU7EUfcRybZf9J191TMOBhd+2+rEi+As/MP8Juo8XpLO23NklRTaO6/R6rKjKO8aGykvtUeDY5oZQXL+2Cx+OJaBnS3lJsJf7Rxa7QYijZaqLAUfq0zSuCHO7wNyd/N7mwTcFgQDn9PoxfXoFx2RQ44z5IqR9hI0EQhKrJnDlzeO6553jrrbfo06cPW7Zs4e677+bpp5/m0UcfDWpfUxP7xMKMtVmM/fpf/ndJJxp7cmDfLgDad+7G8C7BSYG8fLNsD0/8soF3rumGc8HyoPWNGjYgQ/Ewe8OhoHUdO3agcMdRtpWsGz5kkF98UjTjaFzwBqYVHwLgPmUkDc55iWGG2Fzjnlk9h6J8NftduJjn6kp1/D1WRWQc40NlJ/cRMVTJRFN81aOx2HiDRYudSsgAziSbWVcMxWIZUqKwOnlaDuBoUktqF26DBW/C4OCnpIIgCJVNWTKdPvroo1x33XW++NXOnTtTUFDALbfcwsMPP+zn7g01P7FPNNz1pZr97d5vVnNV71JX6SKXJ+xneOiHdQDc9ulK3fVWi5l6CfrTEavZTHJC6b7TkhKw6CRR0B1Hjwf+eAb++Z/6/rR7MA16AlMMRdC9vHNdT27/dBmPnNex2nxfZaE6/R6rMjKO8aGykvtI1GAVRKtLEizqV1TsdPuJFy2pNv+biLPEIuSKVwIFLwYDGxtcoL5e/D4UHom8jSAIQgWjzXTqxZvpVFvnTkthYWGQ4DGZ1Em2J8r4zBMZbVa4Ar1YHx0cIe5JFqMBq1l/OmIyGvwyyNlCtAtCUeDXB0qF0MDH1Qd4ZRBCAD2a1WbRQwM5v2ujMm0vCELVRcRQFUR7G/bWVNh9tJAHvv1Xt31ygBhy+SxDpXvSu7lr3e5CCa1AstK64cnsrKYkXfhWVNsIgiBUNLFmOh0xYgRvv/02X375Jdu3b2fWrFk8+uijjBgxwieKhNBos8LlF0cnhkJhiiCGtLWFjMYoxIzbBT/eAYvfAwxw7ng4Y2zEzSIRjWeHIAjVD3GTq4JohUtCSSG7d//aFrJ9ss3/xu3wxQyVPoVzuj1Yzf4Xcq0AivpBqMGA+/T7MX93Ayx6F/qOgcT0KDeOjiKHG5vZGN1NTxAEgdgznT7yyCMYDAYeeeQR9u7dS/369RkxYgTPPvvs8foI1Qq7U5ta2xUyHjYaK5vZZMRmCi2GvImEosJlh29vhA2/gMEEF74NXa+IfntBEE44RAxVcRKjuAkkWwMtQ8HZ5FyKgrXEELhkxxH+75tVfjeuaDPVAXjaDYOMjnBwnSqI+v836m0jcTjfTo9nfqdX89p8c1u/uO1XEISaTyyZTs1mM48//jiPP/54JfSs5lGssQx9OG8Hv605wA93nkZGWoJv+bFCB+e9MTfivszhLEOGGMSQowC+vAa2/QkmG1w2BdrXvGQHgiDEF3GTq+LYLJG/ooSAG4VeAgWty9xl7yxgx+FCtmcX+JZFW8MIAIMRzvw/9fXCiVAcv4wes9apAdBLdhyN2z4FQRCE+KK1DAHsyynmu+V7/ZZ9vngXe44WRdyX2RTeTe7qPs2om2zlsh5NQu+kOAc+vlAVQpZkuOZrEUKCIESFiKEqRLvMVAAu6NbYt8zrJheK9g1SubJXUwZ1yPAt8wofh6bo6v3frGLfsdA3pWiyyfnR8QKo11a9AS15P7ZtwxBrNwRBEITKx65T1LuuJuV1KPREj8VkxBLGTa5OspVFDw3kpUu76O/TmYv5kwtgz2JIqAXX/wgt+0fsiyAIAogYqlJ8e3tfvru9L5ecohFDOilEtXwx+lTOaFOf96/vSfsGqpjyWoSKNJW+Z63L4u4vV4T0345ZhBhNpdah+W+CPT/GHejjQdSQIAhCVUebQMFLoCeDVUfgtKqfgjkgHjRSAgVQ44p0Exjk7OGMzc9gOLgGkjNg5HRo2ivajyEIgiBiqCqRmmChR7M6fhf8xAhuciaT2tZgKL2ZuBRVDBU6/G9WG/bn8dWS3br7iTabnB8nXwx1WkLREVg6KfbtdRDLkCAIQtWn2BlsGQq0FgWKHlCtR4HJcSxGg65wglIxpEv2Fswfn0uK/QCetCZw4wxo0CmK3guCIJQiYqiKE8kypL3ZeF/fOGUp6/blUhQghvLsLh6culp3PzHFDHkxmeGM+9XX898AR2Hs+whE6nsIgiBUefQsQzsPFzDklb/4dOFOAEw6AqdOspVABwCT0RjRMhRE9hb4cBiG3L3k2RriumEa1G0V24cQBEFAxFCVJ5IY0t4otD7Xw1//J8gyFI6YY4a8dLkc0ptBwSFYNqVs+9D2Q7SQIAhClcdrBbqiZ1Pfsol/bmVTVj6P/LAGALdOkdX/DGwTtMxsMoQspmrSc40rPAKfXwYFB/FkdmZum4chrXFwO0EQhCgQMVTFSYjgJmfW1M0IDEDNKXJGfZwQhcEjY7KUFrOb9xo4i8u4IxWp/C4IglD1KS6JSR0zoDWDO2bqtgl0m1v12BBaZ6QExYZaImST88PlgK+uhSPboNZJuK78CoclrYyfQhAEQcRQlSeUZejzm/vwzW19AyxDZS9SWiY3OS9dr4a0JpB/AFZ8Uvb9EOQ9IQiCIFRBvELHZjFSL0U/i1xgXFGtJAsQ7A1tMhqxmvTvdX5iyOOBn++GnfPAlqamz07J0N1OEAQhWkQMVXH0xNDDwzvQr3U9ejWv47fcHCIANRrKJYbMVjj9HvX13FfUCuBl7kfZuyEIgiBUDt5bhs1sCpn8QC+uSI+oLUNzJ8Cqz8Fggss+hIwOMfVZEARBDxFDVZxAMfT56D6MPrOlbttQN6RoKJcYAuh+HaQ2hNy9sPLzMu9G3OQEQRAqD5db4eaPljDxzy1l2t5mDk5+UCtRtQDp1SKCYA8Ak9EQ0rPBJ4bW/gCzn1JfD3sRWg8qU38FQRACETFUxQmMGWpVPyVk2/K4yZU5Zsh38AQ47W719dwJ4I4+XkmLaCFBEITK4/f1Wfy+/iAv/7YxYtvA8B2DQV8MeTObFjv1LUOBD70skbLJ7VkG39+qLuhzO/QeHbGvgiAI0SJiqIqTYPa3DCXbzCHblsdNLi4WmVNuUIveHdsF/35Vtn5onhmWOcOdIAiCEBVFIQSLHoFFT1NsZrXGXUC8j1cERWsZCpdNLqFwH3xxJbiKoc1QGPps1P0VBEGIBhFDVZxEq/9NJilMqu3AbHKh0MtQ546H8LAmQb+71Nf/jAe3K+ZdaLtRbtc9QRAEISwGovcoCGyZWvJwzmL2X+MVQSHFUFAChWBBBZBCIa1n3QQFByGzE1w6CYzhy00IgiDEioihKo7WMmQzG4Mqd2uJ1k0u2RpsXYqbEabnjZBUV017uua7mDfX3iTdIoYEQRAqFL0yPqEwBlqGEtR7SWC8qkvx4HIr2GOwOgW6yZlw87rlTRKPboCUTLjqS7ClRt9ZQRCEKBExVMWxaaw4zesmh20brWVIz9UublYYWwr0HaO+/vtlUKK/GQb2Q7SQIAjC8WH3kUJGf7yUxduP8OYfm3ny57VBpiHvvUTPxc3hVigOYRkKRPF4gsTQI+ZPGWBaiWJOgKu+gPSmIbYWBEEoH6EDUIQqgfYmc+eA1mHbmqO0DCVZg90MvCIkr9hJsVOhfqothl4G0Hu0WoD18GZY9wN0uqRMu4mL654gCIIQksA4IC8Pfb+afzZnM2tdVshtU0rEkF7yg2Knv2XonJMbhNyPovjv4zrTTEaZfwPgwIBXadS4R/gPIQiCUA7EMlTFMRgMjL+sK+OGtWdEl4Zh25rDuNBp0bMMeYXHJW/Pp+/zs/lw3vbYO+vFlgp971Rf//WyeqeLEm0iB4kZEgRBqFi0dw1t0ppDeZHrxaUmhBZDdpfbFzN076C2vH5V95D7cXs8Ple7s4yreML8EQAvOq+kqM2IiP0QBEEoDyKGqgGX9GjCrWe1CvkEz0u06bH1LEMej1pvYlNWPi7Fw5M/rytLV0vpfYtaIfzQetjwS9SbafVPDBpKEARBKAPa24o2TjOtpFZQOHyWIZ3kB3an4ssqd0qz9JCps0F9CGYxGWhr2M2bltcxGTx87TqLt90jMMUS1CQIglAGRAzVIJxRqiG9BApuxUNucWn2t2itTCFJTIc+t6mv/34p6gAgbSuxDAmCIFQs2mxyWtfkWlGJIbWNvmVIwVFiGbKZw2eAcytgKDjEZOvLpBqKWKh04GHXTYChtOiqIAhCBSFiqAbhilYM6bnJeTwcK3TEt0On3g7WFDiwGjbNiGoT7c1YsskJgiBUHi7N9TctIRoxpIocPTF07aRFbMsuAPQTLGgxuIrgi6toYshmm9KAWx334iwJaRYxJAhCRSNiqAbhjDLhQLJNz03Ow7Eip++9S/GUvxBrUp3SSuF/vRiVdUhrDZKiq4IgCBWLn5ucO0bLUEnMkF5ZB23MUUKY+ngGFIZvfQr2LuWYJ5kbnf9HDim+9eX2UhAEQYiAiKEaRLSWoaQQbnKBlqG4ZHPrOwYsSbBvBexaELG59smkaCFBEISKRSs1nJpAzWg0iNdNLpLlJ9z6+X0WUWvbL2C0cKtjLDs8/omCwtXWEwRBiAcihmoQTnd06iHRYgoqtKd44Fih02+ZKx5qJLkedL5Ufb1kUsTm4iYnCIJQeWivs9rrbzTX/9Kiq+FjgrT18rRcbPybhqveUN+MeI1Fng5BbSSBgiAIFY2IoRpEtAkUrGZjUIFWxeMJEkNxq/PT8yb1/7ofIf9Q2KYut7jJCYIgVBahBFA01/9wMUNa9BIo9DOu4QXL++qb0++F7tfobmuKsn6eIAhCWRExVIPo0DAtqnZWs9FX08GLEhAzBOGfDL782wY+X7Qruo416gaNe4LihBUfh23q1rhpSDY5QRCEikV7nfXGDH28YAffLNsdcdtw2eS0JARYhnoZNvCBZTxWgxs6XgADHgu5rViGBEGoaIKDR4Rqy02nt8CteHArHl6bvTlkO6vJEBTw6nR7WLcvx29ZqCeDWw7mM/HPrQBc0atpdNl+et0Ee5fC0ilw2j1g1HerkJghQRCEykNrjXcpCnuPFfHYj2uj2tabZCEmy9CepXyS+D8SFDv/JvSiy8XvgzH09pJNThCEikbEUA0iwWLiPwPbMGfjwbDtLKZgN7nF248EtXOFqHqqLf56MK+YhrUSI3fu5ItgxjjI2QVbfoe2Q3WbuWN00xAEQRDKjhIQM5Qb4CEQjmZ1kwCCPA28fHd7X4wGTa2g/avg04tJUArJrt+HFtd/C2abr/28Bwewek8OXy7ZxZyNqku1iCFBECoacZOrgQQKnUCsZiPGKFwPohEje48WRdmpROh+rfo6TCIFf8uQiCFBEISKRBtqqpZUiH5bb8rsUGKoR7M6dD+ptvomax18fCEU50DTU6l381RSU/1duxunJ3JOpwZ+9ydxkxMEoaIRMVQDiSSGLCYj+XZXxP24QmSn0yY22BOtGALoeaP6f/NMOLpTt4lbxJAgCEKlEZhNzkPs191IbnJkb4GPL4CiI9CoO1zzNdhSQjbXyh9JrS0IQkUjYqgGolcAT4vVHFoMXXvqSaTaVO/JUAkUtMv3HotBDNVtBS3PBjyw7MOI+xY3OUEQhIpF+3DL6Vaitgw1rJXgex1WDB3ZDh+NgIKDkNkZrp0KCbXC7luMQYIgVCYihmogWsvQmW3rB60P5dIAcGG3xr5Upu4QMUNai01MliFQEykALP8EXPag1dpjimFIEAShYgmM04z2IdRlPZr4Xmvjero2TQegd/M6cGw3fHQ+5O2D+u3h+h8gqU4Uexc1JAhC5SEJFGogWjF0yknp3DuoDRe9NV93fSDpSVbMJTe2UJYht5+bXGFsnWs7DFIbqTfH9T+XFmQtQeuaJ5YhQRCEiiW4zlDkenVPX9iJK3s19Vv25S2nklvkpE+Luvy0ai/ntTTCx+erSXPqtITrf1SLcAuCIFQxxDJUA9G6yVlMxqBsPOFcGtKTLL72oWKGtD7mOTFkHgLAZIYeN6ivdRIpSMyQIAhC5REYM+SIULy7cXoi153aLOih2qkt6zLk5AbUSrJwXedkan9zKRzZBuknwQ0/Q2qDqPskbnKCIFQmIoZqINqblMVkCBJD4WKKaiVaMJfUfAhlmdEud7giP0UM4pTrwWCCXfPVDEMaJJucIAhC5RFoGQr1EMyLOUJMKoVH4JMLIXuj6gVww89Qq0n4bQRBEI4jIoZqIP5iKNgyFMpNLtVm9msfjZucvSxiKK0RtB+uvl7qbx3ytwzFvmtBEAQhehS/mCEFZwTLkDlcdrfiHPjkIshaA8kZqhCq3TzmPolhSBCEykTEUA1Ea/kxGw1BNy+b2Yh3UZuM0vSmtZLUauLeJ3+uEDdFrcWmTJYhgF43q/9XfQX2fN9ibaFXiRkSBEGoWLRuci63JwoxFGLaYM+Hzy6D/SshqS7c8BPUax3HngqCIFQMIoZqIBZtTJDBEFRg1WIy8uvdZ/KfAa157uLOfsuh9MlfaDe50td2l7tsnWxxFtRtDY48WP21Zt8ay5CIIUEQhApFCXCTc5TFTc5RCF9cCbsXqWmzr/sBMjqUuU8SMyQIQmUiYqgGok2dbSD4SZ7FbKRdg1TGDmlHz2a1fcu3ZxcAYCppH9pNrlQNlclNDtS7nbcI65LJvjzaLnGTEwRBqDRcAWLIGeGaHuQm5yyGr66BHf+ANRWu/R4adilXnwziKCcIQiUiYqgGEnizCvRqSNBYjgwGAw8Nbw/Ajae18Ns+pGVIs7jMYgig61VgToCs1bBnSdAx3ZJAQRBUHDGmsBeEKPHPJhdFzJA25tTlgG9GwtY/wJIE13wDTXqUu09iGRIEoTIpkxiaOHEizZs3JyEhgT59+rB48eKotvvyyy8xGAxceOGFZTmsECWBCRMC39ssJr/3t5zZip/GnMb9Q9v6tQ9lGVICssl5yipakupAp0vU10s+UI/p1lqGRAwJAvmH4I0e8NdL4HYd794INQw/N7moYoZK7iduF0y9GTb9qj7UuupLaNY3Ln0SMSQIQmUSsxj66quvGDt2LI8//jjLly+na9euDB06lIMHD4bdbseOHdx///2cccYZZe6sEB0GQwQxpFNnqEuTdJKsag3eUsuQ/k0x0GIUqS5FWHrepP5f+z0UHJaYIUHQ4vHAL/eoRYrX/gCeMsboCUIItJdvdywxQ0snwbofwWiBKz6DlmdVYC8FQRAqjpjF0IQJExg9ejSjRo2iY8eOvPPOOyQlJTF58uSQ27jdbq655hqefPJJWrZsWa4OC7Fj0ogjgyFCalQiW4YCxVC5XOUanwINu4HbASs/9csmJ1pIOOFZ9SVs+EWdcF78Lphtx7tHQg1Da4FX6wxFkU1OccPCt9UFQ56BNoPi2ieJGRIEoTKJSQw5HA6WLVvGoEGlFz6j0cigQYNYsGBByO2eeuopMjIyuOmmm8reU6HMaBMoWIzGIMtRIN6scqFjhgIsQ+URQwYD9Cr5XSz9EMVd+uRbUmsLJzTHdsOvD6ivzx4HDTqHby8IZSCwnEFUbnKbZ8HR7WrmuFOuq+guCoIgVCjmWBpnZ2fjdrvJzMz0W56ZmcmGDRt0t5k7dy6TJk1i5cqVUR/Hbrdjt9t973NzcwFwOp04nc5YuuzbTvv/RMLtduPWxBmYjJHHwWhQRUixw3+8va8dTv+4hYIiO7Vs5cjF0e58zLaHMRzdTnfLCrbToeQ4Zfu+qzon8u8xXtT4MfQomH64HaM9F6VxL9y974AK+KzRjGONHWMB8HeTc7qV6NzkFpVYhU65HqzJ8e+UGIYEQahEYhJDsZKXl8d1113H+++/T7169aLe7vnnn+fJJ58MWj5z5kySkpLK3J9Zs2aVedvqh/rVHtu+mtlZq33vUdxMnz497JaHs42AkRUr/yVh/6qg9atXrwFKkzDMnP0nGYnl622ntFNpdWgmIxzTmFoihpYvX4FnV821Dp1Yv8eKoaaOYcuDM+m89x9cRitz0i6jYMbMCj1euHEsLJRMdjUZbWxmNJahps6dsGsOGIzQa3SF9Em0kCAIlUlMYqhevXqYTCaysrL8lmdlZdGgQYOg9lu3bmXHjh2MGDHCt0wpMcmbzWY2btxIq1atgrYbN24cY8eO9b3Pzc2ladOmDBkyhLS0tFi6DKhPNmfNmsXgwYOxWCwxb18dadMjn51HChnUIQO7S+H/Fv8OQILNyvDhZ4fd9pdjK1l79CAdO3VieK+mvuXecWzfsSNs3ehb3ve0M2jXILV8Hc5uDe/O5EzDShqRzT7q0aVbN4Z3aVi+/VZBTsTfY7yp0WOYvRnzpFsAMAx5hrN63Fhhh4pmHL2WeaFm4g6IGYpUZ+js3O/VF+2GQ+1mFdKnpnXK/tBTEAQhVmISQ1arlR49ejB79mxfemxFUZg9ezZjxowJat++fXtWr17tt+yRRx4hLy+P1157jaZNmwZtA2Cz2bDZggOFLRZLuSY+5d2+OtGxSW06NlELqhqMpTc3s8kYcQws3mxzhhBtDf6puZWSdg6Xwk+r9nF663o0qJUQW4cbngzNz8C04x+uNP/BBNflGI2mGv19nUi/x4qixo2h2wU/3wmuYmg1EFOfW/wSoFQU4caxRo2vEEQslqFa5NMrp8RKeertFdanMWe35miBg+Gda97DMEEQqh4xu8mNHTuWG264gZ49e9K7d29effVVCgoKGDVqFADXX389jRs35vnnnychIYFOnTr5bZ+eng4QtFyoOLSptSNlklPbq2LIFcJ3PDCBgjeb3NtztvLK75uol2Jl6SODY+9or5tgxz9caZrD666LJYGCcOIxdwLsW64Gpl/wphRcESqcQMtQuJihK01/YvXYIbMTNDutwvqUbDPzwiVdKmz/giAIWmIWQ1dccQWHDh3iscce48CBA3Tr1o0ZM2b4kirs2rULo7EcwfRC3NFmj/PViAhDaZ2hKFNrO1Ux9MdGtdZUdr6jTP2k/Xkc8qSTYTjGEONSFM8puNwKV7+/iPppNiZefUrZ9isI1YF9K+CvF9XXw8dDWqPj2x/hhMDlZxlSQlqGTLi5zlwSW9bnNhHqgiDUGMqUQGHMmDG6bnEAc+bMCbvtlClTynJIIU5YohCq5hjrDDlK0mFHc2vMt7t4e84Wzu3ciI6NAuK/TBa+8ZzNHYbvuc70O7s8o1mx+xiLdxwBYOLVURxAEKojziKYeisoLuh4IXS+9Hj3SDhB0LrJLdh6mJwi/eyBg43LaGLIpsCcTnLnyyqre4IgCBWOmHBOMExRuMl5rUehiu8pgW5yzujrDL0+ezMT/9zK8Nf/0V3/hWsgbo+BvqZ1JOdu41BeaYp1j0fc5oQayh/PQPZGSMmEcyfIU3eh0tA+3Fq+6xhbDxXothtlngHAinoXgCXGmFBBEIQqjIihE4xoxJApZsuQKoaimb+t3x86M5XH42G3Uoc/FNUdrvWur8jO14qhyPuvDIocbq6btIjJc7cf764INYEdc2HBRPX1+W9Act3j2x/hhCLw4VYgz1zYiZMNO+hj3IDTY2JFw0sqqWeCIAiVg4ihE4zoYobUn4VX9OQVOxnwvzk8O32D33IvRQ43ecXRFWZMtJhCrvPu9hP3IABa7v2ZYzk5vvWBiRuOF58u3Mk/m7N56pd1x7srQmWw7S9490yY9bjqzhZPinPhh9sBD5xyA7QdGt/9C0IEIiWqubRHE55pNBeAX5XeFCdkhm0vCIJQ3RAxdIJhjiJmKNAy9N2yPWzLLmDKgl1A8M3zwamr6fzETPYdizxRTLaFDlPz7vcfpTM7lEysrjya7JketP54c0hjrRJqOP9+A59eAvtXwbxX4e3TYOf8+O3/t4fg2C5IbwZDn43ffgUhSsIkjwPAXJRN5yNq4oQprqFR3UMEQRCqE3JVO8GwxJRNTnV/094ss4vh+5X7dLfLyo0sEhKtpZahYqfbb51X7Hgw8rl7AACnHPwOKFl+vLTQ4a2w9Q9fBwodruPUEaHS8Hhg3msw9WZQnNB6MKQ2hCNb4cNhMO1+sOeV7xgbf4UVnwAGuOgdsJWzcLHAxIkTad68OQkJCfTp04fFixeHbNu/f38MBkPQ37nnnluJPY4vxwodutcnj8fD5qw89hwtDFrnvc6HwrTiI8weJyuVliz3tImqPIMgCEJ1QsTQCUZMCRRKxIl2k6dXmNl1pOyuQtoCkocL/FNwa93gvnGfhd1jobljM10NWwE4/825zClJ310puBww50WY2Ac+uQj+fA6AQoc7woZCtUZxw4wHYdZj6vtT74Srv4Y7FsIp16vLlrwPb/WFLbPLdoyCbPjpLvV1vzHQrF/5+32C89VXXzF27Fgef/xxli9fTteuXRk6dCgHD+pfM6ZOncr+/ft9f2vWrMFkMnHZZdUzU1qB3UW3p2bR+YmZQes+X7yLwa/8zekv/smKXUf91oWzuFtwYVgyCYAPXecABswmmTYIglCzkKvaCYYlihuZKSBmyBjHzFZaa9CRgHpE2pvyUdKYpvQB4FrT7wBsPpjPyA+XxK0vYdmzDN47C+Y8p1oGAP5+Cea9HmTREmoQzmL4dhQsekd9P+RZOOc5MBohMV1NcHD9j6pbW85u+PRi+OEOKDoadrd+eDzwyz1QcAjqd4CzH6mIT3LCMWHCBEaPHs2oUaPo2LEj77zzDklJSUyePFm3fZ06dWjQoIHvb9asWSQlJVVbMbTlYD6gL262HizNELe5pJ2XcIahYcbFkH+AfEtdpiunAtF5FwiCIFQnylRnSKi+RGUZCogZKosW8ng8fsVevRS7Su+8hwv83eoCb+KfugZxsWkuI0wLeMZ1LTmkxN6RWHEUqBaghW+BR4GkujDsJTi6A/54GmY9Sq869zCd3hXfF6FyKToKX1wNu+aDyQoXvq1f76dlf7hjAcx+WhVNKz+DLb/DueOhw4jIx/n3a1j/MxjNcPG7kqY4DjgcDpYtW8a4ceN8y4xGI4MGDWLBggVR7WPSpElceeWVJCcn66632+3Y7aXXrNxcNTOm0+nE6YwugYwW7zZl2VYPl6vUPc7hcPhdf13u0gc4BcUOv2O6wqghbzrtlZkX48wrmS54lLj1OR7EexxPVGQc44OMY3yIZhzjOcYihk4wYkqg4EuZHbsasrsUEnQyxxVpXMyOBLrJBYih5Z42rFOa0dG4k0tNfzPJPTzmfsTEtjnw03/g2E71fefL4ZwXSlMd2/Ng3qvccOQ1Vhjv5CdFXJtqDDl71EQJhzaALQ2u/AxanBm6vTUZhr0AJ18EP94JhzfDV9eq74e9DCn1QxxnL0z/P/V1/wehYdf4f5YTkOzsbNxuN5mZ/pnOMjMz2bBhQ8TtFy9ezJo1a5g0aVLINs8//zxPPvlk0PKZM2eSlJQUe6dLmDVrVpm31bIrH7y39F+m/4rWgLN9hxGvI8iKf9dS5/Aa37rDR0zolczuZthCd+MW3AYzPxaW/k43rl/H9KNr49LneBKvcTzRkXGMDzKO8SHcOBYWBsdAlhURQycY0QS/BlmGynCcUGLIz00uQAwF17sw8Kl7EM8ZJ3G9aSYLlQ6s9TQvQ28iUHQUZj4CKz5V36c1gfNegbZD/NsNegLseRiXTmK85W0KnDag+gZbCyUcWAOfXQp5+9UkCdd+B5knR7ftSX3gtrnw14tqwoW136upuIe9CJ0v8zerKgr8eAfYc6BxTzjt3or5PELMTJo0ic6dO9O7d2iL77hx4xg7dqzvfW5uLk2bNmXIkCGkpaXFfEyn08msWbMYPHgwFoulTP3WsnpvDuNXLwJgyNBzsJlLH3wt+nkdHNgDQLNWbRg+oLVv3Qe7FkJ+cP23kSVWIUOnS2ic1hv2bQGga5fODO/ZpNz9jRfxHscTFRnH+CDjGB+iGUevdT4eiBg6wYimzpDXMuRwKew8XIDTre9GkWgxURQifsbucgPBP2CtGDpW6G/i1Cvy+oP7NP5r/oJmxoNMsz3MVqUhzFkDnS6Feq2D2sfMup9g+v2Qn6W+7zUaBj2un9nLYIDh/2PWyq0Mds3hLcvrsO0saHlW+fshHB+2/w1fXgP2XKjfHq75FtKbxrYPS4L6m+l4Afw4BrJWw9TRsPpbVVTXaqy2WzpJtT6aE+Gid8Ekl994Ua9ePUwmE1lZWX7Ls7KyaNCgQdhtCwoK+PLLL3nqqafCtrPZbNhstqDlFoulXJOe8m7v24+5dB9GkwmLRfP7MpQKI4cbv+PpXd4zOMq5RlVYGfvegWVj6YMtm8VcJSd58RrHEx0Zx/gg4xgfwo1jPMdXEiicYESTQMFrGfrl3/2c9fIcpi7fq9uuVmLoH6LdqS+gtOIpUPwoOmKokASudjzML+4+FHsstDLuhznPw5s91EKY899QXY9CsDkrjzGfL2dTVkAa5Lws+Oo6+Po6VQjVbQOjZsC5/wuf4tho5Cnjncx098BmcMIXV8GepaHbC+XD44FVX8Gnl8JvD8PuxeEjvmNh9beqa5w9F07qBzfOiF0IaWnUDW75U02IYLLC5t/grVNh2RTI3gwzH1XbDX4qPkJe8GG1WunRowezZ5dm91MUhdmzZ9O3b9+w237zzTfY7Xauvfbaiu5mpRHocuzRWN0DH2BpLfLPXdSZm09vwbXmWVgMbhYr7aBRN79Y02geqAmCIFQn5NHkCUZ0qbX9BdPqvTm67dKTLBzILdZdZ3cp2F1uJv6xhTPa1qdX8zqA/404sL5FqBSvaz0tGOO8mxQKGWxcxisdN8PWP9VCmPtXqZPMZv2g86XMt53OhLnZvHBJF1pnpHD7Z8vZcjCfBVsPs+zRwerkeuXn8Ns4KM4BgwlOvwfOfCDqQPY8F9zlvItJvMzprFUn1COnQYNOUW0vREnWOtVqt3Oe+n7LLFjwJqQ2xNh2OPXy6oMyBD0LZETmvwkzH1Zfd7wALnovPokMTBY46//URAo/3gl7l8LPd4MlCVxFavKFXjeX/zhCEGPHjuWGG26gZ8+e9O7dm1dffZWCggJGjRoFwPXXX0/jxo15/vnn/babNGkSF154IXXr1j0e3Y4bWo/MwGup9lIbWBrA2/bz0X3o16oeOIspWPkXuNQiq73xL4kgRVcFQahpiBg6wWhRTz9TkpZoi+qFtQy53MxYc4DX/9jC639sYccLamyN1mIU6J6h5yanJZ8kvlfO4JVrX1DrtKz7AVZ/p2b/2jkPds6jl8fE7UoXvpsygP/ePdaXbvZwgUPNCPfzPbDtT3WHDbvC+W9Cwy5RfV4vRQ43dqzc4ryPdc3egT2L1TpEN86Auq1i2peggz0P5rwAC98Gj1t1Kzv1NjXJwcYZkLcf07JJnAZ4Xnsf2p8LHS5QEx6YreH3rShqfNjCier7PrfB0OfAGBzfVi4y2sNNM9XP8Mcz4CwEWy24YKKapluIO1dccQWHDh3iscce48CBA3Tr1o0ZM2b4kirs2rULY8DYb9y4kblz5zJzZnBtnupMkBgKYxny1nfzCZ4135HsOspeT11+U3oBYNTcEyS1tiAINQ0RQycIn97Uh9/XZ3HT6S0ito3GegSRxJDiFx90IKeYBrUS/G7EgQkTghMohCG5nvqEvdfNcGw3rJ0Kq7/BcmA1A00rGFi4AueLb/KmpTs/ufvSxJANb92sTkrNCXD2Q2oxzTLEbdhL0oMXkgDXfANTzlPjRD6+AEb9Wj5Xq2qGy61Q7FJIscXhUuLxwJrvVLGSt19d1v48OOd5SD+p5IB22DYHZc0PuNb+iLXwMCz/WP1LqAVth0HH86HVALAkBnTWDt/fqiY5ANVdrd9/ypY7PhqMJrWgarthsOhd1QJVq+oEntdExowZw5gxY3TXzZkzJ2hZu3bt/FzIqjMOt/ZBk/9n0ha0LrS7/EofeN2TTUbD/7d35mFSlOfav6t6m41hgGFm2HfZZFEQRAVRNiVxTY5LPNEQo1+inJhDjhrjdzQmJhjjMST5XBJz0MQkYmJcEiUKoogKgrLvmyDrDOvsM71VfX/0VPVb1VXV1T09Mz0z9++6uJiuruWtd3q66q7nee4n9je49hkAwIuRWYgi9pBA1D8einlCSAeDYqiTcMmwYlwyrNjVum5zwpPVDOX64x+v1ftP4frz+xoEkrm/hVMndPN6976yGeP6FuG2iwbGxMfF9wAX34MZD/wOV3vW4Gr5YwxCBb7s+QRf9nwS2zAMYMAlwNW/zlgERwl0hfz114DnrwBO7wNevDYmiApKMrL/bOfLv/kIu8pr8OmDM9GzS2JxuWtO7o6lxB1YFXvdbRAw9xfAsFnG9bwB4Jw5iA66HG/LMzF3VFd497wF7HwTqDsBbFkS++fLj7kBjrwaGDYbUCIxo4QvPgJkX6yH0NhWaq7ZYwgw9/HWORbplDy5bDd+/d4+/XXUJPDEl+/vPomvPbcWL915oWFdWZaAQ2uA8q0IywEsiV6mb8OaIUJIR4ZiiCTg9slfsjS5iPCkcv0XZ3HdeX1MNUPGbdyKoeU7yvHqhqN4dcPRmBgS2K/2wS8jX8Uv8RWMkQ7gas9qfNnzCbyIoOCKh5A7+fZmpSnFXPKEMasq5IKewK1vAIs1QXQ98I1/Arnd0j5Oe2FXecyY4oM9J/HVCWlEPUJ1wAePA2ueApRwLGo39fuxiE2SGh5V8kIddClwzkxg7hPA4bUxd8Cd/wSqj8QiQNtfAzwBIK97LNrk7wLc9KdY7Q4hHQRRCAHOaXIAsObz0/F1o7H3vLIEfByLCkXPvQF5u3vi5vNiTohimpzbNGpCCGkvUAyRBNxe7Iry7MVQKKIgEo1fgM/UhRCMKIYnlGb3ODsx5JUlQz3RaVN/ImskbFUHY2tkMH4auQWAhLcHTcWIZqZ4NIYSo1k+D2LpT5ogqtgK/PkG4OuvAYGCZh2vw6KqwM5/AG//MCZcAOCcK2JNbrsnT+VMQPbETDQGXBRLqzu6Adj5RkwcnT0QE0IFZbG0xhRrxAhpbySKocR1FEWFLEt6ZChQexTY9SYAIOfiu/DxdSP1VDoaKBBCOjIUQySBHJ+7i11hkpqhsJAGV1kfTrDbNqdymF/Hx+NBbTCivxZFljtiF/JjlQ0YUZZ6c0QR8xgNT1x7DAFufR14fm7MVGHJ14Cv/TUzLmUdidP7gaX3AvubbJCL+gNXPh6rrckEkgT0nRD7N/MRoGIb8MWamNGC1vOHkA5MssgQEDOs8cuSHqHvsfNFQFViRiSlowzNtmmgQAjpyPARD0mgIODOqtipZ1HQFBmqbAgnuhi56DMEJIozuyawyThd6yailMjxqgZUN8YaxCYUJpvHXDoa+Pe/x2pWDnwAvPJNIGpsLttpCdXHnNWevjAmhDz+mKX5XWszJ4TMSBJQNgaYfCeFEOk0OPUZMq+jqCpy0Yhuu/4Se2PydxLWFSNDbg12CCGkvUAxRBJw6wzmdFEMRqIG0VJVH0oqhuystQNeo+1xKE0xlM52J6obMWXhexj3SMx6N8EBz2qXfScCX1sSq1XZ/Vas30zTims/P41LHv8AW850ohsKJQrsegt4ejKw6hdANAQMmQHc9Qlw+YOAP6+tR0hIhyIh6m7x3aoZ2EQVFdd5PoYnWAV0GwicMydhXY8hMsTbBkJIx4JpciSBLjkuxZCDJXEwrBjETWVD2OAkB1iknFlcsP0eOcHvIBxJzwo3FEldDG04VAkg7sZkFmxmRzydQdOAG/4IvHwLsOVlQPYCI6/Gr17cgW7RXLyzJxc/aKgE5G5p2Xvboqox+/BgDRCsBYLVsZ+jYSC/B1BQCuT3jDUHzSSqErM4P7M/lgZ35vPY/6f3xfo7KU3RscK+wJWPxSyzW8rSmpBOjjmV2LpmKPZ/VFHwDc/bsReT7rTsuSWmyTEyRAjpaFAMkQRciyHHyJCCqCAU6kNRQ90PYGGgYJHK4fNIkE03zY0mRze3pCOGxEMriupqzDrDrwCu+y3w928Bm/4MbPoz/uJF/K/uyXti//vygZxCINAFCBSafu4a+9kbiDmvBWubhE41EKoVRE9N7F+oJiZMnM8KyGsSRgUlpv+Fn7uUAjlF8UlQVaCmXBA8+/GsbzUGSccxdOlJQAnaH9KXH0tVm3Yv4E/e+JcQkj7mCLZVmpz2IGeSsgXneI5C8eVDPu/fLfcnftWzZogQ0tGgGCIJ5LtMk5MdxFBjOArz5fdkjfFmOTHKYiGGvHJCBKpeEFVi88BkpFtrpDH2kWW46zJjfyK7wJDOmK/GojCfPQ80VuLA0eMoQAO6oB45UlO0JFwX+6c1Gs0IUpOgavon+4D6U0DtCUCNxn6uPwWc2O68G48/Joz8BUDlodg4Ba7QHiIriEW/ug0EegwFug8Begxu+n8IUNjH8okzISTzuHGT09b5d+lfAID6UTeiIKer5f7oJkcI6chQDJEE3OaEO1lw1wUj8HuN+zGLIXOUxSpNzueRE7Kp6kLxyNCp2hC2H6vCtGE9HcUZkGZkSPi5NhjB42/vNrzvGBnSGHVN7B+AOQ/+S69d2vuj6fBFG4FgFdBYHY/4NFY3pbcJP0eCMUESKIhHjfwFguApMC7z51unoSkK0HAGqK2IRXlqT8R+1v8Xfm6sjNX3VB0WJkQGigbEBE73IXj440YcVMtw0xXTceXFkzKb8kcISQu3bnI4vR/TpY0AgIbxt8OuEQDT5AghHRneuZC0kSUJb/7HJfjuSxvx+SljxKC6MYyiPL9h2YmaRsNrN0W+fo+ccPGtD8UjQ1/69Yc4URPEwuvH4OZJ/R3HG2xmZMgKOwc8Owz6xOMHcvJjtTythSwD+cWxf6WjndcNNwJ1J5uEUVXMArtoAOCN/17/sOotAMBV+f0phAjJElxHhtY9B1lS8X50HEYXD7XdnxgZooECIaSjwW81kjYeWcK5fbriJ9eem/BeTWMkIS3NHBlKalMN65qhumA8MnSiaZ9vbUmeYpZezZDzU1C7RrF2mM8lq/HlAEX9Yu54Q2cAxcMMQsiqDoEQ0va4aVugNFZD3fgiAOD56BXo4tBSwcPIECGkA0MxRNJGe0BoTocDYpEhs6NRUjFkaaAgJwgIMTKk4SR0CpsMIdIRQ8lwlSYn0JHuI1IVgoSQ1sGuOfSTN4zT05vzdv4NUqgW+5Ve+LzLJOT67Wv62HSVENKRoRgiaeNpKqT1C2kTmvCobogk2E4frWwwvHYTGfJ7rdLkEt3k7FLgJg3qjv9zacz0IB0DhWSX/Q4dGUoCtRAh2YnZjEYTQ36vjK65PgAqCrf/CQDwx+hsDC0rdNwfm64SQjoyFEMkbbQLpJhDPqhnrAS3pjGMcDR+AQaA/SeNdUUJDUztIkOyOU3OfWTII0m6WGuRyJCDIjh8ph43PLsG7+6o0Jd1IC1k+fsihLQ9CeY0TS9lSYJHljBO2o/AmV0IS368Fr0YQ3vaWSc0bSfcKbBmiBDS0eC3Gkkb2SJNbkhxrIfMwdP1eGdbOQBgcNMyTThoTxbNQsKcVgc0NV01CQhzvyIACNn0HvLIkj6+UAsYKDiJofte2YJ1B8/gW3/8TF+WzPGuPUExREjbY1UPZI4MafV9shRzAb3J8z4AYG3uVFSjAENLnMWQ0Vq743yHEUIIQDFEmoF2gQwIYmhQcbyhZk2TaBnc09hkM6dpfTf2rz6vlNBnqLoxUQyFo6plQb8siqFmNl21wkkQnKxNbELakW4jWDNESNtj1Z8toTl002tJklAgN+Jqz2oAwKuYAQDo3z3P8Rg0UCCEdGQohoglWu2PE16PVZpcfsJ6g4uNTx21Qt1Ea+3EY1ilyVmJmnBU0dPyRDxSvKYpZPF+c3li2R6crg3iH5uPYd2BM4b3rIRSKjVDi97dg6t+85FlWmA2QC1ESNtjrs0ErAwUYv/LkoTZysfIl4JoKByMtdERAIC8JI22te9gryy5bnJNCCHtBYohYskL35yEIT3z8cK8C3DdeX1w7fje+NUNYw3raDf2Yppc326JTxj7dss1mCzk+JrEkOkaHm26qJcWBvRlPos0OStCEcXypsAjy/DpkSHrVDonkl33V+05iWue+hjffWkjbvjtGsN7VkGjVG4kFr27F1uPVmHJp4eTr9wGpNpjiRCSeawiQ+aorZgm9+XwMgDAiWE3orHpwVKuz95JDohnATAqRAjpiLBLIrHk/P7dsOL70wEA04eXAADC4TDqPt+AH35m/Nh4BavVmFOREb9XRu+iHBw8XQ8gLobsUjl6dc1FRXUsxcznkVxdgEMRm8iQDIOBQm0wgiXrDuGKc8sshVs6HDnbYLncOjKU+v4jLVDrlAlYM0RI22NVa2nXdLVL1S6MUPYipHpQMeg6NHx6AIALMSQnZgEQQkhHgd9sJCXElkLazXCB34viAj9yfR70KcpN3MYjo0BIu9MuvOZIjnZNLyvM0ZfVh6KuUsuCUcVSNHhkSa9pCkUV/OSfO/DoWztx7VOrk+4TsI7uuKW5aXIa2ZqVIqbiUBgR0jZYRcS1aNGid/fg+qc/xtajVQCAPvv/CgBYpkxEg787GsKxaLlTjyEg/r3lZY8hQkgHhJEhkhLitVDPQ5clfHjf5QCsG7D6ZMnw5FH72ZzdoaXJ5QkX5rP1YRRZRJvM2EWGZMlooLBq70kAwCkLcwMrmmMSYHGPklZkKFt7E4n6x8q8ghDS8lhFhhRFRVV9GIve3asvy0EQpQffAAAsiV6OW4IR/W84mRgqKQzAK0uWD7sIIaS9QzFEUkIUQ6JQEC+mUwb3wJrPT+uvvR5ZT40DgIDP2k1OC+yIhgmV9SH0yPe7GptVU1WPLOmpHTHHOVe70mlOWYyVQEin+DhbC5bF31+WZvIR0uGxemATUVTsO1ljWDZXXgtvuAYVcik+VkbjasGYJVmaXHFBAO/85zRXD6YIIaS9wTQ5khLifbldAf3/fmOi4Qmi12MdGbKz1hattM/WhVxHU6wKiT1S86y1mxPxMDs6rdx9AkcrreuLnMjWmmWFaXKEtDlWD4EUVcW+E7WGZTd5Y72F3sudAxUyaptaFPi9squ6zCE9C9CjIJB0PUIIaW9QDJG0KbCx387ze3Fe/yL9tU+WDZGjHBsxpKV7eITwU3VjxHWamFXNkCxLuoFCMA0xZBY0yRAFonh6B07V4RvPf5ry8YHs7U0kpgFSDBHSNti5yYliaIh0FJPk3VAlGR/kzwYQb16dLCpECCEdHYohkjI/u3YU7po+BGP6dLVdR0yLs40MCTfQFdWN+muPJOE704cAAB64coRrO9c9FbUJy4yRodSttVNNkxPPSdQHB0/XpXxsjWxNkzNEhmizTUibYFUz9Mg/d+Cfm4/rr2/yxKJClX0vQ42/JwDgyeV7AFAMEUIIa4ZIyvzbhL7w+Zxzx3N8cZ3t80gGcaRFibQb6L9+dhj3vbJFf98jS7h39nDcMLEfBvbIw/y/bHQ1rrv/siFhmRgZsjJYSEaqN/lRRYV2qoYUuxQPLW6brWlyovBrgX62hBAXWLnJAUB5dSMAwI8wrvd8CAA4fc5NkPcYv1DykpgnEEJIR4eRIdIi5HjjF1ifx5gmpxsoNN1Mi0IIiIkhWZYwqDgfkiQZDBVSxSPHHe5CaVT5p5r+ZVdHk+p+DCmELiNDu8qrMf8vG7D/ZGKErCVQDVEwqiFC2gKrNDmRWfJ69JBqUK52Q3W/y+A1fZ/mMDJECOnkUAyRFsGQJifLyBNea0IpahNOMKfFNae1hZgmF1XUpDcOZlLN/ooYHNas64dS3Y9bLXjtUx/jzS3H8Z0/rU/tYGkiasvmWJATQtLHKk1O5CbPewCAv0YvhezxwSMbL/vJbLUJIaSjQzFEWgRzmpx4wdV+tjMnMBsmNKfPjixLht5HVs5LTqSaJieuL55ecyJDbs+/MRw7t4On6lM6VroYI1+tckhCiAm7NDkA6CdVYKpnGxRVwl+jl0GWkBAZYpocIaSzk5YYeuqppzBw4EDk5ORg8uTJWLdune26r776KiZOnIiioiLk5+dj/PjxePHFF9MeMGkfGA0UjH2G7Ky19fVNF2sxTe4P35yEv3/nIozrV+RqHB5Jgk8ILaVqr90cESNumWoWmfi0N9UsQTuXv0xDa21CWp5NhyvxxDu70Ri2NoBxigzd6FkJAPhIORdH1J6QJSkh8h7wUgwRQjo3Kd81vfzyy1iwYAGeffZZTJ48GYsWLcKcOXOwe/dulJSUJKzfvXt3PPjggxgxYgT8fj/efPNNzJs3DyUlJZgzZ05GToJkH8Y0OaObnBY1UlQVNY3hhG3NNUJi36FeXXNwTmkX16lzHsFAATDWDW05UonaYAQXDSm23T5Va21t/UOn63XrWiD1mhrxaa+Uorl2fqB1bm4M1toMDRHSIlz71McAYrWX98wclvC+XWTIgyhu8KwCALwUvRwALMUQIYR0dlKODD355JO44447MG/ePIwaNQrPPvss8vLysHjxYsv1p0+fjuuuuw4jR47EkCFDcM8992Ds2LH46KOPmj14kr2IYshsoKC9F1FUyyakHnOanPAp1VLGvLK7j64sS5CkuCASIzdX/7+P8bXn1uJkTdB2+1Tv8RUFaAxHMe0X7xuWpyqqDLVHKW5bEGidLvGKmv4YCSGpse1YleVyu8jQ5fJGlEhncUotxLvKBACx71Jz5N0u4kQIIZ2FlMRQKBTC+vXrMXPmzPgOZBkzZ87EmjVrkm6vqipWrFiB3bt3Y9q0aamPlrQbxJohc58hTQypKnC8sjFhW4/pUynWzGhPNV1qIV1YiXVDZk7VOoihVK21VRXVDYnRrlQNBiJK+iloXQKtkyYXZc0QIa2GXb2jnSmM1lvoleg0hJuSQKwiQ/WhSMK2hBDSmUjprunUqVOIRqMoLS01LC8tLcWuXbtst6uqqkKfPn0QDAbh8Xjw9NNPY9asWbbrB4NBBIPxG9Tq6moAQDgcRjiceKOZDG2bdLYlcVKZR0kVc6ii8MnxC7b4c1W9hRBRVcMxJKH6RolGEA6H3dfRqArC4bChbihhlWjU9pzCkdRuFIKhEMIWhgf1wcT9O81jQzAkrBdJOufijVKuX26Vz3o4HJ+bcCT5GDN77Oz5m1ZVFduOVWNoz4J258zlZh6zYY6JfQTISgyV4TSmy5sAAC9HL9OXy1KiW2dDOPWWA4QQ0pFolUfIXbp0waZNm1BbW4sVK1ZgwYIFGDx4MKZPn265/sKFC/HII48kLF+2bBny8vLSHsfy5cvT3pbEcTOPW89IAGI3hu+9uxzl9YD2cdv02Tr9508+26ivp7F3zy4srd2pvz70hQwtiLnqg5XoHgDOnIovc2L/vr1YGtwDJewBbGpv3vtgFfYWWG+//Xj8PNzw3nsrmxqQGv+0Nm7ekrAfp3msaIjvY+u27Vh6epvjcWvC8fWrT5/A0qVLXY85XfZXx4+5d99+LA3tbfFjVoViv8VCf+x1NvxNrzsp4c/7POiXr+K/xrbPlCOneayvbx13QuKMVu946HQ93tp6HLdOGYD8gBcRi4jRDZ4P4JFUbJBG44DaS18uWUSGmCZHCOnspCSGiouL4fF4UFFRYVheUVGBsrIy2+1kWcbQoUMBAOPHj8fOnTuxcOFCWzH0wAMPYMGCBfrr6upq9OvXD7Nnz0ZhYWEqQwYQe7K5fPlyzJo1Cz5f69RTdERSmce8PSfx+90bAQBzr7wCX5yuw5PbYqmUl029BL/e/gkAYNjI0cDnxqji6FGjMPeiAfrrjUt3YVX5IQDAjMsvR6+uOXjt9AbsqjqVdMwjRwzH3EsH4+c7VqGqKjElDwAmTp6CCQO6Wb53/OODwME9SY+jMXXapagPRYHNnxiWnzNiFPD5bsMyp3ncW1ELbFoNABg+0jgfZlRVxb1/3wbgOACgtKwX5s4d53rM6bL2wBlg+2cAgEGDBmPunHNa9HjBcBTn/ngFAGDzg5di5XsrsuJv+k//+ymAszhcJ2Hu3LltOpZUcfM3rUXmSduiiZ6vL16LL07X49CZeiy8fkxCxEiGghu8KwEAB/t/BRC+dmRJSqgZuvScni06bkIIyXZSEkN+vx8TJkzAihUrcO211wIAFEXBihUrMH/+fNf7URTFkAZnJhAIIBAIJCz3+XzNuvFp7vYkhpt5DAjv5wX86JIbf/pYkOvXfw5apH74vR7D/n2C9WuOP3Zsr8ddtMbn9cbG61AzFFFl2/ORpNQ8RmSPBxEkPqlVLKJS3qaxWaEKRVGSZD8+ANh8uBJvbD6uv46qaJXPuSzHfweS7DzGTHC6Pv4ZCimx+cmGv2nR7a+tx5IuTvPYXs+poxFu+q784nQsUvfGpqMxMWRKk7tE3oq+0inUyQW44oY78V+PrtJr+jySZGi6euHg7rh3zvDWOQFCCMlSUk6TW7BgAW677TZMnDgRkyZNwqJFi1BXV4d58+YBAG699Vb06dMHCxcuBBBLeZs4cSKGDBmCYDCIpUuX4sUXX8QzzzyT2TMhWYX49FGWJeT44xdg0WmuIZSYomFO4xANFDTbbfPTTTs0Mwan9YMR+zSRdKy1rc7Jqr+Rk6lCNAU3OXNhdapmDekiHqY1jimWYqmgYwPpXJj/zuubvmfM1tqacULd8K+iJL8LPLIEpUlISVLM0EbjW5cMRn4rGa4QQki2kvK34I033oiTJ0/ioYceQnl5OcaPH4+3335bN1U4dOgQZOHJU11dHe666y4cOXIEubm5GDFiBP70pz/hxhtvzNxZkKyjrGuO4bUogMQ+QnXBROFg7jNkeK/pjtiuV8b4pmasmw5XGtb3mS3qBBodCohTdYyOKqplDr6lGHLYd1h4M5mbnFmI2LlOZZpoKzddFX/j4uFO1QaR6/Pwpo50OMR6IKu/a1VVDWlyxajCLHk9AKBq1NdQAu07MLaOLEuGh0tOLpuEENJZSOvuYf78+bZpcStXrjS8fvTRR/Hoo4+mcxjSjhncswBP3jAO3fNjKXF5ghjqkR9Pk2sIJ7q1OUVxPEnE0KvfuQi/fHePLoa09bwObnJOkaFUrbUVBWiwEkMWyidq0ywx9p4gNJKMwZwm49SRPpOIAqg1mq6KR9COfaYuhMmPrYRXlrDvZ21Ur8MelqQFCEaieGntIf11OKrib58dNqxzqjZkiAx9xbMKPimKjcpQdCkdBcD4XSlLxu9XiiFCCGklNznSObn+/L76z16PjLU/nIGooiLH54FHlhBVVD3VQ0S2sKbW32u6dosXeL9Hxi9vHI+8gAeyLBkasupiyKExkVNkKJ00OavIkNVTXacAjvhEOFmgxyyGWi1NztALqeWPJ56Xds7bjlUbXrcJzNgjLcBzqz7HE8vi5i2HztTj3le2GNY5eLpO+OyruLEpRe6l6GX4j6ZaS7GJtbnPkFPEnBBCOgsUQ6TVKC2Mp845iSG7qI/4nuFppwx8aWzcPlaMAmnCKt2aoVTvsWNpconqxSpNzim1LJJCzZDZWjfsEHHKJIaaIYcxhqNKRm66DHVUTT+rrZCeR0hb8OHe5G6Z1Q1hPRJ8obwTg+Vy1Ko5eDM6Bf/V1PhaTDuWTJGhACNDhBDiolELIS2A9rTSqvu5kxjSa4aEp50eUyRJvNi7SZNrDCsor2rE6xuPJgiLlNPkVNU6Tc5CDDlFM8TUl2xNkxPFiZ0o+X/v7cXoh9/BtqNVzT6eKB61c6YUIh0Vsc7SjtpgRP/OusnzHgDgH9GLUI8cBLTIkGz8rpSZJkcIIQb4TUjaBO0CnXZkSIz+mNb3ClEIjwsDhWAkiht/twbfe3kTfvfh54b3UjUGiCo2bnIWuW5WIqc+FMF9r2zG8h0n4vu0GMPWI1WY/csP8P6uEwlpca2VMiYKILvUvCeW7UEoouChN4xNYz/5/DTe2V6e0vEMkaGoFhlKaReEtBtyfMkvzzWNEUQUFV1RiyvlTwEAL0UvBxCP+ohfj+Y+Q36myRFCCMUQaRu067GltbYp0qNavGeIDJnFkJwolJzS5BrDit674+/rjxjeSytNziLtzioyVBtMjIo9t+oA/vrZEby0Ll44bSXI7vjjZ9hTUYt5L3yaUI9k1ZE+VdxExIxucs7rmkXvTb/7BP/nxfU4WtngfkwW4isbtBBtvklL4DoypKi43vMhAlIY25UB2KoOAmCdAmeuGWJkiBBCKIZIG6FFbywNFJzS5CxqhsxCR0yJ0/sMJYkMaew/WYdH39yhv04nMtRocU5BCzE0+1cf40R1o2FZuek1YC1MahrDhmMC8SfJzTVQWLa9HOMeWYblOyoc1xMPk0w8ib9ncd0ztSHX4xI1nlX0i/VDpCOR400uhuqCEYQjUb23UCwqFPv+k/QHRkLNkAxaaxNCiAl+E5I2QXaoGXLTUNVoF2tc3yc4x8X7DDlHhkR+/9EB3REu1ZqhqFAz9N0ZwzCyVyEAe5OGN7ccN7y20mxWgR7xnLUaodymJ8migcLeihr8/O1dqKx3LzrufHE9aoIR3PHHzxzXM7rJuRdDYsqgU0qkmWQGCm1pKEdIpjGnyc0dU4b7rhiO26YMwOxRsb5+NY0RlFRtxXD5CBpUP96IXpywH8mUJif+rVIMEUII3eRIG6Hd9FulyZkjQ1ZP/K1MEqxex93n3EWGNKobw8jxeVK21lYEN7muuT5dhAVt7LvNxg7mFEHARmgIq0X0yJAHQNhgoPDMyv14deNR9O2Wi1smD0jlVBw5WtmAnwgRtGSeDQ2C6BWjZKmIIUOanJpYM6SoKjxs+kM6CGKa3OCe+Xj6lgn666dX7sOyHRWoDUZw5ak3AABvKReiBnkJ+xH/ImTJ+HfEmiFCCGFkiLQRupuchfOalSAwIztEhgxpclpkyMlaO6wk3JRXN8TS0FLNvIoq8chQrs+jizarOiIgsf+RlWg7Wx/Cj/6xHZubGskCpshQUyRIu3kSU8gqm87DSnQ2h28sXofTdfFo0z83H8Ou8mrb9cXfs1g/lYIWsokMWb9PSLtH+Nsw1wV2CcSeY0bqqzC+OpYityQy3XI3sqnPkLgriiFCCKEYIm2E5gZnJTbcRAucIkOiwNANFBzS5N7aejzhRrqqIRbJSPUGWxGarub4ZL1WyTYy5FDvpPHGpmN4YfVBXPPUx/oyUf9pkSCtYFo0UKhrMmnItMPc3hO1CcuuWPSh7fri71lMk0tlWFGDtXZsH6J5gfb2hkNnseHQWfc7JiQLESO84YjxD6UgJyaGxlYuR0BtxF6lDz5Th1vuxylNzqk+kxBCOgtMkyNtglP0p3u+P+n24tNORwMFrelqik9Aq5sMClI3UIAuhsTIkF3NUEKanMubE8fIkHATpdXqZFPURIwMpTIuxSIyJBJtEqLXP70aALDzx1cg15+8CJ2QbET8jEdMjZQLAj4AwLSapQCAJdHpgIsUUVnKru8CQgjJBhgZIm2C2bRAZGCP/KTbW9lna/g8iVEjpzQ5kaK82E2GliaXsrW2YKCQ4/fEI0MWbnLi+DTcmEcAxvSyiMlNTowC1TXV6qRqBNGSiGIoFbFpvDm0rhmqE+zK6yzMOVoCmtiRlkBMjQubivIKAl6Mlg5iaGQfwvDi1ehU/b0e+X787uvx+iJjzZDUan3ICCGkvUAxRNqEM3X27mbmp/lWN5uiADJHmTyWaXLuPuojyroAAKob0xMRiqKivCoIIGaNq4mwRovaKCDxKa17Q4H4eloD0njNUPwmqj4YbVrW9jdAmhGGGCVzekr98qeHsOjdPfF1k/QZUpvfXomQrMGQJhc1R4a8uMqzBgDwkXcyzqJQf+/nXxmL2aPL9NeS8P0oSdn1YIQQQrIBiiHSJoSa2RjUMTJk0YPIbcSlZ5ccAGJkyPrG4Z4ZwzC4Z2IE649rDuJUbUwM9eqao6fB2UWGdlfUYNaTH+D1jUcBuDOPAIyRobAWGWrqSxKOqrrw0KzLU033M7PuwBnM/8sGHK9ybpJqvtESGz9qETNDmpzDuO7/+1YsencvdpfXNO07/p4mAFULh7lspjYYwcZDZ9kTqYV46qmnMHDgQOTk5GDy5MlYt26d4/qVlZW4++670atXLwQCAZxzzjlYunRpK43WGfEBRoIYyvHiPHkvAGA1xhvec/pkSZLULv5OCCGkNaEYIu0So3228T0xCiTrNUMuxVBBAADwzvZy/Nuzq7G7osZyvf7d8/Dnb01OWL7hUCUA4KpxvTGwOF83c7ATQ7/94HPsPVGL7728KTbeNGqGok0qQYyoKWpMKDjVDFVUN+Kq33yE363a73isiupG3PDbNXhzy3G8uOYLx2iO2TVPdKuqbjKlcFMzJIoFLd3NaKBgnSaX7Xzl6dW47unV+MfmY209lA7Hyy+/jAULFuDhhx/Ghg0bMG7cOMyZMwcnTpywXD8UCmHWrFk4ePAgXnnlFezevRvPPfcc+vTp08ojt0aM8CakyfmAMdIBAMBnkSGO+zE/X2kPfyeEENKa0ECBZAXd8nw4Wx/GVyf0TXjP6tLtcUyTS6wZMltYW+H3yHrN0JYjVY7remTJMaXt0nN6xo7bJMLcFi27Xc/KTU5s0hiOKpCkuGiwehr8H3/ZiK1Hq7D1aBXunGZ/Q7V0a7wx7MHTdXrUzIr6UBR5/vjXitgAtqohjLKuOQhGk4shQy+ippO1MlAQz0tRVENKUDbe9Gni+rWNR3HN+Oy46e4oPPnkk7jjjjswb948AMCzzz6Lt956C4sXL8YPfvCDhPUXL16MM2fOYPXq1fD5Yn/3AwcObM0hOyJGhvp2yzW8V1izHwEpiBo1F5uDJYb3zFFHsxjqmuvL7EAJIaSdQzFEsoKX7rwQq/acdN0Y1ErwaBgNFBKXOVGY4+5PQpYlx5Q2bwoiTMRtbY/RTU6z1vYYloXFCIzpyXIkqmDdwTOujtUg1DsdPtOAs/X29V7mfkZi3UOjRZqcXf2CmEap/X7NBgpe0/aKCsgWVtvZCA2NM0soFML69evxwAMP6MtkWcbMmTOxZs0ay23+8Y9/YMqUKbj77rvxxhtvoGfPnvja176G+++/Hx5PogthMBhEMBjUX1dXx/pqhcNhhMP2Dwjs0Lax2zYk/N399pbxhvU8xz4FAGxVBkExJXhEo1HjPoW/g3A4jFsu6IONX5zFrJElaY0720g2j8QdnMfMwHnMDG7mMZNzTDFEsoIhPQswoqww+YpNOIkh8bWcxFp73YMzMOmnKwDE0lIKXT419cqSo9DR0t3cijCNqJJ6LZXWV0jsWB+NqgY3NXNk6GRt/KauZ5eA85gEQXPgVB3O1jtHhjRUVTWIOy3tJ+iiZkgUTNrvM2KKDHlNyxRVNUQRaSHceTh16hSi0ShKS0sNy0tLS7Fr1y7LbT7//HO89957uOWWW7B06VLs27cPd911F8LhMB5++OGE9RcuXIhHHnkkYfmyZcuQl5eX9tiXL19uufx4uQxAxk2Do9i3/kPsE94bd+gfGAhgkzo0YbvP1q9H6ED8s99Q74Emv7V6qC8XATh+DEuPb0p73NmG3TyS1OA8ZgbOY2Zwmsf6+vqMHYdiiGQFTgYHlo1ZpUTBo+EThI8niYFCSZNhAhCLLBTmuBNDsiTBKeijHc/vdRcZsrrhdzy+sNt4ZEhIk1MUgzAxR2DEJrDJ3KXEMdUGI9hjU0cFxA0bzNsB8boHNzVDVvbbioVZgmJymBNrro5WNuDVDUdw86T+6FHgLPjMHD5Tj/0nazF9eEnylUm7RFEUlJSU4He/+x08Hg8mTJiAo0eP4he/+IWlGHrggQewYMEC/XV1dTX69euH2bNno7DQ/YMcjXA4jOXLl2PWrFl6mp7I30+tB86exnnjx2LuecaUSu9zPwcAbFYS01snnD8Bs0bFP7dP7v4Ip4Kxm4a5c+emPM5sJ9k8EndwHjMD5zEzuJlHLTqfCSiGSJvw2PVj8Ic1X0BVVYzvV2So9XCDU2TIaxUZcmlM4DYylKxmSHtPjNY4UVwQazRrTmezw5Am17SNzxMbU1RREVWMPXfMERgxOmNn+61hrr1xqqcS0+TMDlgRCzFkV9djJZiiVjVDwiFU1Sjsbv7dJ4goKtYeOIMXb080u3Bi6uPvAwD+csdkXDSk2HHddOJPqX7eiTPFxcXweDyoqKgwLK+oqEBZWZnlNr169YLP5zOkxI0cORLl5eUIhULw+43NnwOBAAKBRFHt8/maddMjbq+qKk7WBlHSJQfaV0HAvP9QHXByJwBgU5MYCnhl/W9a9ngM64sPCDryzVlzfw8kBucxM3AeM4PTPGZyfukmR9qEmyb1x7/umYq3vzcNj31lrOO6VveNYsQlUQxZRIZc9hkqzHX3fMAjO/cE0sRXjsvIULe82I2X28iQeGRtG69H1o8bjhojQ+YIjNjrx87pDgDu+vP6hPeTGShomB2wNHEUEo4dsRF/IQuTBcXCTU5MK4yqquU6H+49ZTveZHx28Gza25LWw+/3Y8KECVixYoW+TFEUrFixAlOmTLHc5uKLL8a+ffugCJ+hPXv2oFevXglCqLX4v69vw6SfrsDSrcf1v40EJ8zjmwFVQaW3GBXoDgDIE5wkA6bvHMpuQghxhmKIZD1WwYOCQFy0mNPkvJ7EqJF7AwX3aXJOBgra09gcv7vIkHaOyepc/uOljfh43ylLa22vLOkpgpGomiCGqurDuiARBU5EUfW6IzNLt5bjX9uOG5Y5RZLqw6LQMe7T6tjNjgyZrLUzXSbUUnVHvEHNPAsWLMBzzz2HP/zhD9i5cye+853voK6uTneXu/XWWw0GC9/5zndw5swZ3HPPPdizZw/eeust/OxnP8Pdd9/dVqeAP689BAB4/O1d8Ycc5ocuRz4DABwvGK0vyvV58B+XD8XlI0owrcnJUocfNkIIcYRpciTrOa9/EfCxcZkohsw3C9Zpcm4jQ5lJk4tHhtyJIc2COllk6J+bj+Gfm48Z7HHDwk2TWHsk1u+UVwcx7sfLMKykAMsXXGoQG0BMoNhFzyqqg4bX5l5CIg0ONUPaa6PQsd5P0HWanNFaW83wjV9LNUdlllzmufHGG3Hy5Ek89NBDKC8vx/jx4/H222/rpgqHDh2CLHwP9OvXD++88w7+8z//E2PHjkWfPn1wzz334P7772+rU9AJRhRBDJn+Lo+uBwCc7TYGKI8tyvV78P3Zwy33xY8aIYQ4QzFEsp4vj+2FiKJgbN8ifVm+GBkyiyHhpl676XTbdDXfZSTHI0mQJAmyBMtoRKo1Q1pKjFs3uSohVU2rM/J4ZD0CFlEU1AXjomXVnpMAgL0nagEY0+RirxXk23gMmIVTY9h+jPUONUN6mlzUmNqW7JhWZgmaM51BDJmstTMBDenaF/Pnz8f8+fMt31u5cmXCsilTpuCTTz5p4VGlTiii6JHVhO+uJjFU33M8ECsdMjRcNsP6NEIIcYZpciTrkSQJ153XF0N6FujLugj9gMzpauLNg3b/bBUZsrpHkCTniI9+zCR9hLTlYiNUJ7QbH7c1Q4Ztm4SBT4wMRY2RITPBsDky5GyiIOKYJheyrweKRFU0hqNYvf+0vsxNnyErs4Ro1CIypKq24ipdWq5xq/sb1NX7T+Hr/7sWn5+sbaGxkGwjGFHiNUPid0xNBVB1GIAEtdd4fXGuw0MXSiFCCHGGYoi0S8TIkFnUGNPmbIqQYbTgFnEjhrRbZLvsO20fTjcpImGLtC+3aALKI/Q+iiiqITIk8sPXtmK/6cb6uqdW4+CpOldpYc5iSEyTM7nJKQp++OpWrP8ibkpgd77BsLHeqTEcNQidiE3qXBptmhzJhsjQ155biw/3nsKvV+xt66GQViIYiep/P4bvrmMbYv/3HIGuRT30xU4RaAaGCCHEGabJkXaJWDNkvjkXn6RqN7NWBgp+GzHklSWEkhy/sqnxqJ2JQuppcs2IDOnW2kKaXFSxjQz9palIW6S8uhH3vbIFf/pWcgtq92lyiX2GXt141LDMts+QEAb6x6ZjmPfCpzi3d9eE7USBpKqAkoE0OXFMbsRhOnVFbm9Qq4QGt3binXQ8wlHV2kChyTwBfSZgTJ+uGNWrEIfP1uPLY3vZ7ktibIgQQhyhGCLtEtE+tiFBDMUv/lqak1U628DiWNf4i4b0wOr9p2NGDbAXOCLafu2iSNoYAq7T5Jpu7l32GRLZebxaH4tHt9ZWUSeIIUmyduUTOVUXTKjzscIppa7BMU0ucd9uaoY0AbX1aLy/kaWpgqqmFOpWVdWynsJNH6TW4sN9J/Wfe3XNcVjTmoOn6nC0sgEXD3XulUSyj7i1tvCpbqoXQp/zkev3YOk9U5Puh5EhQghxho8aSbtEvIltMEUqZFnCiLIuKOkSwODiWJ2RmGrSpygXl48owVNfOx8A8Jubz8MPrhyB3359AgDA42C28MO5IzBjRAlmjow5VNmJoWSRoQtLTOYCLt3krDhdF4tj+Txxa+2ooqJeSJNzc08f8HpciSGnyJAoTMOK2UBBhXm6bCNDDr2PAMFUQdj+uQ8/R3lVo+N2GtWNYVz82Hv4wd+3JB47KoohV7tLGbf3p0fPNug/h9MYzPQnVuKW36/F9mP2jXJJdhIRLPMBAIoST5PrO7GNRkUIIR0PRoZIu6cxlBipWPrdqYiqqi4OxBSjmSNL8Mg15+qvexQE8O1Lh+ivE/p6CNw5bQjunBZf12NroOBcMxQwLU7VTc4Kjyzroi+sGJuuuiHglQ1CwA6nmiFRTIUjiYKvuCCAEzVxq27bPkNJxmGVJvfWluN4a8txu00M/HPzMRyrasSSTw8nNP0NW5g3pEs4quBsfQglXYxRHbdP60VxbBVZC0cVSEjeVHhPRQ1GC2mGJPvRPnv6g5wz+4HGKsCbA5SMcr0fuskRQogzjAyRdk99OLE2RhYakALGCE7XPOfu8uYmrk7Y3YPKSSJDXtMhIooKVVXTigzp+/RIujiLmNLk3BDwygl1PiLatDiNUdw+oc9QVEWPAqN/d7qRISsDhVRwqr8Rjx1MMg4Ahiolc/3Q9U+vxqSfrsC+EzUpjxEwiUuLtMOLHnsPM578wLJuSUxndNtMmGQPYbObnJYi12sc4HH/+6QUIoQQZyiGSLunIZT8htUnRHCKkjRWdYoMJa7rHBmys9b2WiyOKKqhzuYbFw10PQ7tmL6m40bTiQz5PAnRHBE3DWSNN+8mN7mogh75RiFq6yaXLE2umWJIFKnmiIs47qBDFMwKRQXqghF86w+f4m+fHdbrnN40RazcFrWLYzG78x0+24CTNUF8cbrecr4qBfMFpz40JDvR+wxp30d6vVBqKXIMDBFCiDMUQ6Td0+AiAiLWDBXlOYuhb08f4vi+SDJrbTsB4ZUSb+IjUVW/uX/6lvNx5bllrsehHVO76T1TF0ZdMJ3IkIMYcmEGEY4qepTCbKAQVtSEBrkRRcWeipqEfkPJIkPv7jyBujCQht8EACBHUKO1pnkyiCEXkSHxjBRVxZ/XfoF3d57Ava/E65FyfR7bnkpOiHNons9k97hn6+OeiG3sA0FcIkawI+Y0Od1J7vyU9kkxRAghzlAMkXZPvYun96K1dtckkaF/nzwA//Nv41wd2855TosY2T2Rt4oMhRVFf/ovOsO5xeeRMa5vEQDgsy/OpBwZ8iepGXJjE/7xvtO46LH3cKKmMbHPUFRJqIn6y9pDmP3LVVj88QHD8mQ1Q+XVQTyz09OsGiuNmkajGApF4sohlWa0QEwMmRvaAkCe32Oob3J7gyqmxpnT5MRXVhGys3XxyFBz0i9J6yG6ZGq/M59HBiJBoHxr7I0+E1LaJ621CSHEGYoh0u5x89RbTGdLFhmSZQkTBnRzdexkbnIBK9WDxJohwBgZ8spSQhTFzVgmDeoOAFh34IxtnyE7VFV1rBly2zPpeFUjnn5/v2WfIXN049CZegDAgVN1qGkMY+6vPsSid/ckjQwBwOE6CS78HiwRx5YghoSdOjnnaYhnpChAV4vPV47PYxAs7sWQfZqciJURhRgZSicqRVof8ftC+7x4ZAko3wYoYSCvB9BtYEr7ZGSIEEKcoRgi7ZbBPfMBAGP7JnfJ8hoiQ84GCgDgsxExZpKJIUmSLAWRZc1QVNGfBntkyVW/IxGfLOP8Ad3gkSUcOduAU7XJWscaCUWUJGly7utO6oKRxMiQoug3eObaoWBEwZJ1h7HjeDUWvbvXdUQm3ZohcWzOaXKpR4bEhsAauX5Peg11hXGahaThuBa/NlEMMTLUPvBbfDH4ZBk4Gm+2mqq6oRYihBBnaK1N2i0v3j4Zf1x9ELe5MBoQHeKSRYYAY1qdE3bW2qJIyvF5EmpPrNPkxMiQnHKanEeWUBDwojDHi7NC8bxbghHF2UDBZQNZADhTF8LDb2w3LAtH4m555pu+YEQxRGT+9MkhV8exspt2gxh5qg2GEVVUhKMKckwmEm4iQyKKqlpGKr2yZGio695AQUyTM45F3IOWgqeqsc+Q1yMbDBQykU5IWp6ARY2hxyOlbZ4AgKEhQghJAiNDpN3SpygXD8wdid5FuUnXFR3i3NgM+03WyxcM7IbX7rooYT07h2bxeFa9hqzT5IyRoVQsvoG4gLMTaMkImQSJGTduchordp1AtSn9LCxEhhLEUDia8vkCMPQsSgUxUlLTGMHV/+8jjH74HdQ0hhFsVmTIOp3NbnkyjGlyyWuGbvjtGkx7/H0EI1GcrWNkqL1h9RDGK0uCeUJq9UIAI0OEEJIMRoZIp6CkMAc/uHIECgJey1QUM+Z17r9iBM7rn1hH5C4y5C5NLmaTXBd73yPZOtXZoR0zSf9NW0JRxbFmqLn2zFuPVOkOd2axGYwoaT3APlLZkNZYRJFR0xjB9mPVAGK1VmLqnas+Q6r4s3XdVVSI+mmv3RAxRYaOVjbgtsXrcNtFA3HRkB76e1rN0KcHzwIAthypwt83HEn5eKRtsfot+UJVsYarQMpOcgADQ4QQkgxGhkin4duXDsG/XzjA1brmppx2XdzzbQSCOU3OjFVk6KvPrtFvpNOqGWoas13vo2Qkrxlq3tfF3hO1OFbVCMAqTS6KFLMCAQDHKhvTGoudgYKqGt9rTKPPkNUcKqaGum4iNQuX7sRbW+P9icJRBY/9axf2najFf7++zWCKYBY7L6w+aEiVdKo3ItmDldGFfHxj7Ifug4G87invk1qIEEKcoRgixAJz41W7+h2rYnnAaLltFVFJFpxK100OsO99ZMV5/Yv0n5OJIat6hnSxqhlKxwI43fQv8Txrg3HRoAIIReMCyE1kSERREx3ztOWiYLFyfxM5crYev131uWFZJKoaxJlo1R1VVL2/EwAcN0XMGBlqH0RNnwufR4Kk1wulniIH2D/IIYQQEoNiiBALJEky3LDb6ZIuFvVHsgSDkBnduzBhHaumq4b3ZdkgqKYM7oEV378Ut0zub79NU71BKpGh/5x5Du6ZMQxATCCY63xEUnGTS0ZCmlw4vTS5dBGNF2oNkSEVYbHPkBtrbdUocsIWtUFRxSjckokTK0EVVlRjg1fhMGaxZa79Ys1Q+8D80fHIonlCmmKomWMihJCODsUQITaIN+x2xf1dchIjQ2YxcsnQYot14j9b1hR5jE1Xu+f7MaRnQUL6nhWpBJQUVcWMkSUAYpGhkw6GBM1NkxOxSpNz0y8qU4QEsSEKwFhkSHCTazIiWLLuEKobrR36xKf5imItZBRFNTi6JRNDVpHISNQoGBVTZEgch9kFzxxxINmJOWLoM4ihNJzkwJohQghJBsUQITaIzk52YsgqTc58IztlcKIYElexcpvzmNLktEaeTpbf2n5EMWa1vnjsYETRhUko6iyGrMaZLubeS2Zr7ZZGjAxVNQhpcqrRdltVgdv/8Cl+8OpW/NdfN1vuyxyhsbL7NtcMpZO2FomqhlRCc9qdOA6zC160FeeWpI9ZDPWTTwF1JwHZC5SNaaNREUJIx4ZiiBAbxCiMXeaZVWTILIa65vnwf7800rAszwt8eUwZrhrXG6WFOQn78MqSQbQU5fqa9m09kJfuuFBP2RNFlDkdrV/3XKz4/nQMKo41rJ00sLu+TjBpZMgohi49pycmDOiG+64Yjp9ed67tdjNHliYss6oZMtfnTBqUerG4W0RhUufQdBUANhyqBAAs21FhuS8lIU3Owk3OVEuUTAxZ1RSFFWNkyFgzZHxtTu9jmlz7wKxZx0pNLnKl5wK+xO8JN7BmiBBCnElLDD311FMYOHAgcnJyMHnyZKxbt8523eeeew5Tp05Ft27d0K1bN8ycOdNxfUKyBfGG3c7ZrcCFGAKAb00djKnD4hEiCcAvbxiL39x8nmXqm9lNrlueH4B1pMfnkTBFsFkWzR/MouPOqYMxqDgf73xvGjY/PBvd8v3xyFBEwcla92ly153XB3//zkW4a/pQfGlML8tt3vneNNx0Qb+E5Yk1Q1FDRAawN6dIhxpTipt4rAaDY5zqaCJhRlVVg3BRVVg2rlXM1tpJ0tasxFIkqhrEkGpOk3OwBKeBQvvALILHSvtiP/RNL0UOYM0QIYQkI2Ux9PLLL2PBggV4+OGHsWHDBowbNw5z5szBiRMnLNdfuXIlbr75Zrz//vtYs2YN+vXrh9mzZ+Po0aPNHjwhLYl4w273dNXKQMHsRKchptqJa3gtGy3KxjS5psiQlTmCWXzJDmLI23ROfq+s79OQJldtb1VtjgyJx7GrZerXPdfy/KwiQ2YxlJ9BMTTmR8sM6XBiA9SGUFwMKaY0OSd+tnQnLvn5+4ZomjkdTtxvKmly1mJIMaXJiftXDbbM5jQ5RobaB2YxNFrdG/shTfMEAPjmJYMAwPAwhhBCSJyUxdCTTz6JO+64A/PmzcOoUaPw7LPPIi8vD4sXL7Zc/89//jPuuusujB8/HiNGjMDvf/97KIqCFStWNHvwhLQk4g2+nbV2Fxc1QxriYlFb+WwEjhgZKtTEkI1wMr6Or2O2w7YSLQFPbB1VBY47iSHTvrwuxFCuz2P5nnWanPEGviCQuRolANhw6Kz+s+gYVx8yHjfksifP71Z9jqOVDYZ+PmKfoeKCgL481aarVpGjsKIaVLS5ZsjKQEGr82JkqH0g/p48iGK4ojVbTV8MzRldhg/unY7nv3FBc4dHCCEdkpTEUCgUwvr16zFz5sz4DmQZM2fOxJo1a1zto76+HuFwGN27t1w9ACGZQEwLs3Noc5smF9uH9XJrgWM0UChsOo5Vmpz5eKKIMosOq+3FdZyytwKmNDmPQQwZ91vSJYDLhveEJEmWkTKrnkXm2p18f+YiQwAQFUSOaH8tpslFldTS5MyIfYbmXTwQV43rHV+egpucfWQojjlNzqphZ15TjytGhtoH4t/fOdIR5CAEBAqBHsOatd8BPfL1qDAhhBAjKd1tnDp1CtFoFKWlxoLo0tJS7Nq1y9U+7r//fvTu3dsgqMwEg0EEg/HUk+rqagBAOBxGOGxtb+uEtk0625I4nW0eR/fugs1HqgAA0WjE8rxzLYIXHsl6jsSbVwnxdawM4lQlAkUVGrd6pdj6FmrFK0uG48lCDyOfSYhIqpI4NlNzk8IcLxrCUYRNERK/6V5KVaKW5+mRJby3YCr8nti4JDVRXHgtzrmqIWR4nevLbLVDUPj+CAoCqCEUF2HBUBjBsH2vpWSf/VAojFAktr0EBR7E5jAciSIoHCcStfg9iGMNJb4Xjhobq4rjDIUjaLTYRhP04bD159fN33Rn+XvPBkQRPF5uqhfqfV5qnZQJIYSkRGYfvSbhsccew5IlS7By5Urk5Ng74yxcuBCPPPJIwvJly5YhLy8v7eMvX7487W1JnM4yj/lVEoCY2vlg5Up0DySucyYImP+MGhsbsHTp0oR1T5yQoQVjJSk+j2dOx5drvKvPcWzfG9Z+hEM5wJ7y+Jg0IqGg4XhnzsT3V19bDTG3asumjVAPJQoqCR5oLT1zpTC+NzaKvdUSNp2WsLMytq8tG9cbjr1x/XoEPxf3FRurqipYsextfemh2vh7Gl8c2J9wzoeOnTSM9cD+vQnnCgDTeymY3kvBjzak9vX16foNiByMjffI0fgcNQjOaxs2bcaBGilhbBrG32vi8T9YtQpfHInte+/uXThWF9vXjp07UfkF9POpqqmx/IxoHKxJ3H8wHMbxY8f0sa1du07f38erV6NbIHGbaLABgIQ9+/ZjaXiv7fGc/qbr6+tt3yOZRUx1HCc1P0WOEEJIclK6myguLobH40FFhdFitqKiAmVlZY7bPvHEE3jsscfw7rvvYuzYsY7rPvDAA1iwYIH+urq6WjdeKCwsTGXIAGJPNpcvX45Zs2bB50sseCfu6GzzeGkwgucefQ8AcOXsmeiR709Yp6ohjEc2vG9YVlhQgLlzL05Y959nN2Lb2ZMAYrf82jy+WbkJ288aDUjmXnkF/B4Jfzq6FqGIgluunQKPLKH60yN45cAOw7oF+bmYO3ea/vrvp9ZjT9VpAEBJcXd8URuvlZk8aSKmn9MzYWz3f/auXmcysKw7vn59rL5g/kubsLMyNrapF12IZ3Z+Gt/X5AswVWgoe8+aZQBi9t9z587Rl+8qr8H/bDWm0Y4ecQ7ePrLPsMyX1wWoqdVfjxo5Am8eSryBnztlLL40uhg/3vi+IXqWjLHjxmPu2Jjr3RtnNgJnTiasM+rcMWj44ixw4rjlPubOnav/rJ2vyMWXTMXG9/cDp09g3Lmj4T1eg3Unj+Kcc4ZjWGkBsGsTACA3Lx9z515iO9YNhyqBbUbXTRUy+vQpxYbT5QCACRdMBHZtBABMmnwhenXNATZ8ZNimZ/euKD9ajYGDBmHuFcMTjuPmb1qLzJOWR4z8jZebxFAznOQIIYQkJyUx5Pf7MWHCBKxYsQLXXnstAOhmCPPnz7fd7vHHH8dPf/pTvPPOO5g4MfkXeyAQQCCQ+Bje5/M16ya8uduTGJ1lHot8Prx4+yScqQuhrCjfcp1unsQ/IZ9HtpwfWUh1kRCfR79FM9PcgB8eWcLrd1/StG3spj9gUUfjNR3P64nvz+wAl+v3W47N75F1MVRSmKuv4xVqewpyjWIwx+ZzIEEyLM8NJK5jtawmaDQy8Hutv578Pi/8fj9yPUCdfUZbAiri82TnkaBKMsIOJUPieRUEvKg11TnJHg+iqva78sXrNCQZkOJzqahw/huSEiNTEUU1foaE/UmyB7LFZzGv6fOimH4nVudl935n+FvPFrQ0uXw04BzpSGwhI0OEENKipJwmt2DBAtx2222YOHEiJk2ahEWLFqGurg7z5s0DANx6663o06cPFi5cCAD4+c9/joceegh/+ctfMHDgQJSXx55qFhQUoKCgIIOnQkjmmTosMYoiYmWWoCJ5sbrRTS5xH9oi2fSelRnBdef1sR1TIMFa2zqS4vd6AMRu7HsKLmii6YNZWNkZRZgbm1jZgZuNHYDEXkC2RhRNy1MVQ6JRgp1JQiSqoLLeXY2M1ehUNW7bHWucG1srqjbfTc68XdShz5CGZqBAN7n2gfZrOlc6CFlSUekrRVEX56wLQgghzSNlMXTjjTfi5MmTeOihh1BeXo7x48fj7bff1k0VDh06ZHh6+cwzzyAUCuGrX/2qYT8PP/wwfvSjHzVv9IRkARv+exbO1ocw438+AADdTcwJY5+hRGFg19fIvO7C68fgqxP6Gpal6iYHGEVTzy6iGIqvk+tSDJmXWgkws0gDgOpGo7Kx2792fjleAPY9YhNoFMSQ3e8oElVxyqHxrGFdy35CcTc5n0fWz0FRkZKbnGITnTLYaZuEkblHDRCPDNFNLvtRLMwTygtGoaiNxkMIIZ2FtAwU5s+fb5sWt3LlSsPrgwcPpnMIQtoN3fP96JYXTyUK293JCoi3+XYCxQpzFGnO6LKEPj4eYX9+j1kMWRsD+G3EkHg0J2ttEbOOs1rPKjJkxlYMNW1a6FNhHZ+xRmyuGrKLDCkqTtWGLN8zYyVoxD5DXk88MqSY+ww5eZjDKJzM4xOPpf9sExnSonlRl72TSNshitlxTfVCJwvPxYi2GhAhhHQS6NdJSAYQIzl2UQdRJIg/l3QxOivOHWOfFmOODHksIkjiMnM/H6uUNSBW/6JhjAwJ9t4+d/uSTALFKihhJ8pErM4NiBk0AGhyT3NPvRgZshEboYiCM3WxyFBpofMBrPYR6ycUO2GvLBvS5CIppMlZRXnM26WSJsfIUPYTtRBDZ7o5mw0RQghpPq1qrU1IZ8DcnycZd182FL265qA2GMG8iwfZ1+IgMeXMos7eUFfkNk1u5shSbD0a66kk1gxJDsLKrvWJWcP07pqDL43thbe2xB3a7ISOcf/OkaEegdTmWYwM2QnWk7WNUNTYOfTsEkBFtXXKnKKoliJPVeNNW/1eSU8zVFRjU1Q7MXTodD2eXbUfg4utDTuMgiouxhSbNLncJjFkJ65I9qD9OnviLPpIpxFVJdT1OLdtB0UIIZ0AiiFCMoxdcb6IeJvv98q4aVJ/V/s2GyhYiQrZUQxZK5gbLuiLX767BwBiFs3avkSjB5OQso8MmV5LEp762vl4Z9tS/WbeTugY929joNB0zilHhoSmp3ZpcuVVjbF95/mR47XoqNuEXaQlliYXjwzpNUOKu8jQ1xevxRenE/v6+L0yQhHFIIDCEXF/1hE4LU2OkaHsRxOsmqX2XrUvvLld2nJIhBDSKaAYIiTDRNyIIfelLgbMAsQqiiSKCK9HgiTFXM6011b06pqL5+ddgGBYQTehn5IxtU9Crs+ju7LZZbrZmT+Ii5NFhh65erRDzVBsefcUI0N//ewIehQEcP8VI2wjQ+XVMTHUI99vO1eAvZhRFFX//Xs9ki76FBWu3OSshBAQq/0KRRTDuEVBZ3ar04i7ySX/TJK2RUuT01LkNilDUOC3F+SEEEIyA2uGCMkwYRdP4dPUQgnRGStNIUZdvLJkTJtzqNW5bHgJrjjXWK8kmw6QJ9yceVxGhuJjjb/jlAr43vcvxW0XDUzqJpdqZAgAnlkZu9G0i96VV8XS4ooLAo51TXY1R2JtkM8j65G1qDkylGLamibMRMETighpcoqdm1xTZIgGClmP2vTrHC/FnOQ2q0MS6vQIIYRkHoohQjKMq8hQmvt2Y6Agih+PLBsMDaxsvJ0w7z5XEEN2aWx2JycudhJDWmqXXfRIE3td0uwF+pe1h3C8KR3OjGarXdwl4DhGu8iOKrrJyZJ+DoqqGqIzoYiCb7+43vWYtYigKKjEyJBiERmSpLiFOfsMZT9RVYUEBWPlzwEAmxWKIUIIaQ0ohgjJMHb3naIoST9NzrihOXJjXuaVJcNNc34gtZsrc8pbvj+eWWtX92N3arLLyJBW5+SxqX3SlssS8Osbx8JF+ZGBH762Nek6g4vzbWuiAHuTDHOfoXianJpQt/P29nKDqYITPovIUDhi7Ftk3pfPI1uKKJKdRBUVg6XjKJQa0KD6sVvtZ3j4QAghpGWgGCKkHWGuY7ESJMbIkPF9syNcMsy7dxMZsqsZEle3EnEaVmJIfEIubnvluWW4Y9pg230lw06UXTaixLH/k23NkBAZiqXJaSLGutePm55UQPz3Lqb3hc2RIVOaXEBo+srIUPajqirGS7E0zq3qIEThoRgihJBWgGKIkDYg7TQ5OTFCYsbjIIZSxblmyF3T1fhyl5GhplQ+UejlCA1fu+YafV/MfY1SIc/iZrO4wI+xfbo6phTa1QwpgrW21yPZusnp+3FZy+Nr+r2LdUJB0UBBSRQ8fm9cDNmNl2QPUVXVzRM2K0MAJPb2IoQQknkohghpA9JNkxOjFXZ6QhQaYvQmP42nzOZD5Ag3Z+aaHu24Y/p0Tbovp9Ilrc5FHPuJmni/n4E9jD14VKQf9RCbzWoMLi6ALEvwpVEzFI4oqG6MWXj7hKarVjU9gDG60yg0hTWjRYbEdQzW2hZ9hmJpcpoYs901yQKiiooXPj6I8XLMPGGTMhRA6jV+hBBCUofW2oS0EukKIBHR4cwu1cwuTa4oz2+1uiPmlLeAWLtjSiNb+t2p+NMnX+A/Lh9qs6/4z3Zjz/V59GOKYku8z/d6ZIQVQTg0IwPMKjKU11RX5RS9sqvBuVMwRfB64k1X/7b+iKWTn1h7VNUQtj2e9ntvjNikySkqzL4djAy1H15adwgvrNqF/wocAhBzkgOsxTohhJDMwm9aQtoR4s27nTuz2Vpbo2tu6vZrZs1iMDIwvTm8rAt+cu25DvtKniYn1khYnZ5VnVJzqmEKLeZEm2PHNDkX6W1imhxg3ehVFDSV9dZi6JKhxagNxqJNYmQoZDJQsEqTs7LkJtnHpsOVGCV9AZ8UxWm1ED++9QpElPT+ZgkhhKQGY/CEtCPyBDc3q5trINFaW6MoL/UbK3MEJ2Dh6uYWQ9NVOzHksxZ7XXJi5/1vE/slbOPGka1PUS66C81kX7x9Ep6fdwEKcxLnJNcXO5aTgYKbSItPlm3NJPT9JIkMzRhRgj9+c5I+74Y0OZOBgjlNzu+R9d8/3eSyG1WFniK3VRqKy0eWYfbosiRbEUIIyQQUQ4RkiOvP6wMAmD68Z4sdQ4zM2JHJyJBZs4hudLZ9hmz3lTwyJBoliLVAL985BffOGY6HrxqVsI2b2/w+RbmGmqWpw3risuEllvOp2Y87WWu7ibT4vDIc9BQAo6CtrA8lvF+U54csS/o4xcOGos6RIZ83XjPEyFB2oyJunrBdGtbGoyGEkM4F0+QIyRCPXncuLh9ZgmnnWIuhTNQMucG+Zih1MXT7JYOxZN1hXNsk9JoVGRJ+tmuommuTBji8rAtG9S603MYuXdBwbAno2SWA03VGwWElhnL1NLnUa4ZEvLKUdI7ECFNNk/GCeR+Acd41DGlyFpEh0VqbkaHs5HQj8I/Nx6EoKsY12WrvoBgihJBWhWKIkAyR5/fiy2N7t/UwjE1XhRv63l1zU95XWdccbHxoll4/ExAiN8lSwMyIq9uZOYhpcuLNvZOoMIsAKzyyhP+5YRwefG0b7p0zXF8esKgL0hrLWkW+FEWFLEvuIkOe5GlyoiNcvYWbnBblsxJtoQQDBeOYcv0e9hnKcn680Qts3Ioi1GBRTgUAYKdkbUBCCCGkZaAYIqSDYY4M/eiqUXh35wncPnVQevsTBIPfk37fE1EYFBdYiyHRujuTt++yJGF07654/e6LDcutRIaTgUJYURCQPYZ6HTs8LiJDYtPVhlBiZEgbglWz3HCSPkMFOV66ybUTxsmfAwA+V8pQ5+/SxqMhhJDOBcUQIe0MT5LIhLnP0DcuHoRvXJyeEDIjRoZSRdQFdhETQ5NJl2pIdREZkm1EiVOanFWfIW3ek0Vabp4UM3qwSwfUCEdEMZQoWLS6JUtb7iR9hroEvOwz1E7QUuQ2qUNtbecJIYS0DDRQIKSVkBJamKZHThITBdFBzuNgApAOVrUrbnFz/mLNkOj+5oQbzWRX/mMQX03oaXI2fYFO1DTi4Te22x7r1ikDsPD6sQCS14mJtTz14cTIkHZjbCXagkJkSFUT+wx1YWSo3aA5yW1WhlAMEUJIK8PIECHtjFy/B3WhxPoSDfEePlXHt2RYpWu5xTyU4oIATtUGDctEcTKuXxHunTMc/bvnOe7XTc2Q3Q1mjoUY0g0UbCJDc3/1IU7VJjq/aXQT6qGSpcmJdT+NFr9T7XdpJYbC5j5DpnkoCPj0yBJrhrKZuJPcZmVIysYkhBBCmgcjQ4S0M5IJEmNkKLM3Vm6sve0wp8aVFgYS1jGLk7svG4qrxjmbUrhxk7NLkxMjURp5Dm5y+0/WOgohwBjRspr/uy8bov8s9hmqtxRDTcYVVmIoanSTM6cLGmuGKIaylX7SCfSQahBSPdihDmjr4RBCSKeDYoiQdobVDbxIS0aGtB5Kw0oKmr2vCwZ2T1iW7NyscJcm56JGqYk8hzS5zYcrkx5LtDC3qo26d84ITGo6d1HQWLnJOUWGkrnJiTVD0WjnEENPPfUUBg4ciJycHEyePBnr1q2zXfeFF16AJEmGfzk5Oa042hjjNUttdQBC8DGKRwghrQzT5AhpLTKkS3KSmBi0ZGSouCCALT+abSkikmEuX7p3znA0hqOYMKAb7n1lCwBrcZIMNwYKdvNgLYbsDRSSRYUAoCAQ/1q1E2Fa1CmcLE3OoWbImCaXzE2u499gv/zyy1iwYAGeffZZTJ48GYsWLcKcOXOwe/dulJSUWG5TWFiI3bt3669TtYvPBGKKHMCURkIIaW0YGSKknZE0Tc6mz1CmKMzxwWcRNUnGD68cCQCYd/FAAEB+wIvHvjIWl4+I36gmE3pWNCdNLscxTS5xLOYaJyvyBTFkp0W1+Qu7TJOzcpMLCdsqFm5yBQFvp+oz9OSTT+KOO+7AvHnzMGrUKDz77LPIy8vD4sWLbbeRJAllZWX6v9LS0lYccYzxTWJokxLrL2Su/SKEENKyUAwR0s5IFj3xGPoMZc+f+JVjemHDf8/CQ18eZVgeEM4nHSctV2IoBTe5PIemq27EkBgZshNhviaRGmmKDP3108NY8/nphPX0PkMW4wxF4uIpqli7yXk7iZtcKBTC+vXrMXPmTH2ZLMuYOXMm1qxZY7tdbW0tBgwYgH79+uGaa67B9u32LoEtgRcRnCsdAABsVmORIaUTCFdCCMkmmCZHSDsjeZqcsc9QNmFlly2aA6STpqS6qBq6+7Khlsud0uSsomqpRobs0uTikSEFqqrivr9vsVxPE1MBy8iQ0UAhoc+QkCanqLF0wrZIA2sNTp06hWg0mhDZKS0txa5duyy3GT58OBYvXoyxY8eiqqoKTzzxBC666CJs374dffv2TVg/GAwiGIz//qurqwEA4XAY4XA45TGHw2EMl44gRwqjWs3DAbUMQEy4prO/zoo2V5yz5sF5zAycx8zgZh4zOccUQ4S0M6yiBCJeQ2Qo+29+xfGmM1ynyNCUwT3w/LwLLC20ASDXb9F01adZa1ukydUkrxnKDwiRLtMu3vnetNi+hTS5kDmkI6DNjWXNkJgmZ2GgIFprA7HoUUukTbZXpkyZgilTpuivL7roIowcORK//e1v8ZOf/CRh/YULF+KRRx5JWL5s2TLk5Tnbv9uh9RfapAyB2pSoEQyFsXTp0rT215lZvnx5Ww+hQ8B5zAycx8zgNI/19fUZOw7FECHtjJwkNUNyFkeGrBCjFWmlyTm855ElWyEEWPcZ0ubPl2ZkyJAmJ5zPLZP7Y3hZF8O+w1EFoYhRDOX4ZDSGFcP2VmJIFD9RKzGU44UEoH/3PHhkCVFV7bBf+MXFxfB4PKioqDAsr6ioQFlZmat9+Hw+nHfeedi3b5/l+w888AAWLFigv66urka/fv0we/ZsFBYWpjzmcDiM4Kf/CyCeIgcAkuzB3LlzUt5fZyUcDmP58uWYNWsWfD5f8g2IJZzHzMB5zAxu5lGLzmeCjnptJCTryJQs+eYlA/H3DUcwe5R1sXd7iwyJpJPF5dR01a5mR0NMk7tqXG/cN2e4/tpq7ty4son7tEtZ9DVFbCKKiqBJDBXl+lEebjRsb9VnSMQqTS7P54EsS1h132VJx9ze8fv9mDBhAlasWIFrr70WAKAoClasWIH58+e72kc0GsXWrVsxd+5cy/cDgQACgcTeWD6fL62bHlVVE5zkACCqgjdRaZDu74EY4TxmBs5jZnCax0zOL8UQIe2M0b27YtNDs1CYY/1FIEYjrFK9splkUS8rnNLkkmWFiX2Nzu1diH7d4+lO6TjmAfaRLtGdzueNLQ9FEiNDRXk+lFcbxVCyZrdWaXLJhGBHY8GCBbjtttswceJETJo0CYsWLUJdXR3mzZsHALj11lvRp08fLFy4EADw4x//GBdeeCGGDh2KyspK/OIXv8AXX3yBb33rW60y3mhDNYZJRwEYxRANFAghpHWhGCKkHVKUl2hEoCHWhXjaSY3IXdOHYPX+07h6fO+Ut716XG+8tvEoigv8CX2AkkXGxCiO+RY0EymGso3NuVePDCWKoR4F8d+tLoaSCLOoarRkfvTac9MfdDvlxhtvxMmTJ/HQQw+hvLwc48ePx9tvv62bKhw6dAiy8HDg7NmzuOOOO1BeXo5u3bphwoQJWL16NUaNGmV3iMxybBNkScURtRgnUaQvprU2IYS0LhRDhHQwjJGh9iGG7rtiRNrbTh/eE2999xKUFuZg4qPvGt5LVoMk1gyFTaLEqs+QmUmDumPdgTO273ssUuOAeKTHykChR348FUtzo0tmmqEoqh5R+D/TBuPfLxyQdOwdkfnz59umxa1cudLw+pe//CV++ctftsKorFGPbQAQM08wLKcWIoSQVqV95dAQ0o5pLVtjTzuuGUoHSZIwundXdM1NTBsc0MPZ5UusxQlHE9PVrBCtzbvm+rDtkTkoLrCO1InTb4wM2RsoiOchu4wMKWq8z1BnS49rr3iObwRgTJEjhBDS+lAMEdLBEG+F20tkKBNYnev4ft0ctxEFaihqfCQ/uDgfg4vzE7YpLohHbiJRBQUBL4Jha3tsUZiINUhinyGzgUKeYM3tZK0tElXiBgp2vY1IdnF2zq9xffBHeDM6JfnKhBBCWgyKIUI6MJ0hMqRhFXkb37/I9fbmCI0kSXhj/sVYMOsclBXm6MsNYqgpNa0+HLXcp5imZ0iZa4oSRaKq4bizRpUi3+9N2CaZm1wsMhQbCyND7YOwnIMN6jk4jh5tPRRCCOnUUAwR0sEQ4xudSQxZ0btrTvKVmjCnyQFAlxwfvjtjGKadU6wvE8WQJmTMTm4aHpv6LS0yFIoqCEZiQuqc0gL87usTkCc43GliKqm1tqLqhfeMDLUP7D4zhBBCWheKIUJaiba4Re2sYqh/9zz85VuTU6rTshJDGr265uo/i/VBTtsAgOhsLqbJaeYMYmQoz++FJEnIF5q2uk6TU+OWzGk6gpNWJhKlGCKEkGyAl01COhiqYEfV3voMZYo7pg7CRUOLk68oYE6TE+ld5JwmN7DJqMFcY2Rnre3X0uQURXeT06I/hshQGn2GWsuogzQPNw18CSGEtDy01iakA9NJA0NI5z5zZK9C2/fsI0OxA70wbxL+96MDuHPaYMN2dtbaWmQoFIlHhjTBY6gZkty5yUUUBYfO1Ccck2QvkSRRRUIIIa0DxRAhHQyxd05njRIoKTRrWfrdqVi19yRuu2ig7TqGyFCXeGRIS5MbWJyPn1g0OrWLDGkpc+/urND3oUeGBDc5rWmu1yPDI0u2dSaffB7vdcSaofYBI0OEEJIdUAwR0kq01j3qiLIuuGVyf5QWujcP6Ggka7YqMqp3IUb1to8KAcbIUI43Lla651n3F4qPI/6zlZscAHyw5yQA58hQ7Lgy6kLWrnWGYzIy1C6gGCKEkOyAYoiQDoYkSfjpdWPaehhtwl3Th+C9XSfw1Ql9M7pf0dSgd1EuXph3AZ5ZuR+Pf3Ws43aeJH2GRLRUuHwxMiRsn+v3uBJDHmqhdgHT5AghJDugGCKEdBjuu2IE7rtiRIvse8mdF+LI2YZYJAmFmD68JOk2so21tlXkyq8bKCT2GQKAgFdMfwTsMgFZM9Q+YGSIEEKyA4ohQghxwYWDU2+OKdtEho5VNiSsq4kdMU1OFDy5gsvcmD5dseVIVdJjkuyFYogQQrKDzum7S0gbwFvUzofHxkBh5sjShHW1yJAoehoj8bS4XMEYo8yhHowGCu0DNl0lhJDsIC0x9NRTT2HgwIHIycnB5MmTsW7dOtt1t2/fjq985SsYOHAgJEnCokWL0h0rIYS0K8QgjdjzqX+PPGx6aBZyfPFlmhgSewoFw/G6koCw3Mkcg5Gh9kGyhr2EEEJah5TF0Msvv4wFCxbg4YcfxoYNGzBu3DjMmTMHJ06csFy/vr4egwcPxmOPPYaysrJmD5gQQtoLojDxmpwNivL8hgiPVS+hoBAZCgjCqUSw9zbDyFD7IBI1RoYkCegS8OJXN41vmwERQkgnJWUx9OSTT+KOO+7AvHnzMGrUKDz77LPIy8vD4sWLLde/4IIL8Itf/AI33XQTAgH7CzghhHQ0RGFiZZrQUxA1YkRoaEkBAODiocXx9z3uIkM0UGgfmNPkZowoweaHZ+Oa8X3aaESEENI5SclAIRQKYf369XjggQf0ZbIsY+bMmVizZk3GB0dIR8Jr8eSfdGxEAWQlUkQxJKbB/eueqagPRdE116cvE8VSSaH9gyUGhtoHYZMYyvF5mOJICCFtQEpi6NSpU4hGoygtNRb/lpaWYteuXRkbVDAYRDAY1F9XV1cDAMLhMMLhcMr707ZJZ1sSh/PYPL572WCs3ncKN07oDTTs4Tw2g/byWYxGI/rPSjSSMN4yQQx5JNXwfp7XeH6iNXePPPuv7tqGkOt5cTOP2T7H7ZWoYqwZyhOMMwghhLQeWWmtvXDhQjzyyCMJy5ctW4a8vLy097t8+fLmDIs0wXlMn/tGAlLDHgCcx0yQ7XMYjALa1+zqjz/G4QLj+zXlEoDYTfDuHdux9PQ2232dLJehZTZvWfsh7L6+P920FQUntqQ0Tqd5rK+vT2lfxB3mmiHRLZAQQkjrkZIYKi4uhsfjQUVFhWF5RUVFRs0RHnjgASxYsEB/XV1djX79+mH27NkoLCxMeX/hcBjLly/HrFmz4PP5km9ALOE8ZgbOY/NpL3PYGI7ivnUrAABTp16CUb2M31+F+07jbwfWAwAmnjcOc8f3tt3X6jd2YN3JIwCA6758BR787F3L9QYMOQdzLxvianxu5lGLzJPMkpAmx8gQIYS0CSmJIb/fjwkTJmDFihW49tprAQCKomDFihWYP39+xgYVCAQszRZ8Pl+zbnyauz2JwXnMDJzH5pPtc6hK8Rtcv8VYh5TExVFOwPlccoVmrDl+P7yyZNm4szGipjwnTvOYzfPbnjEbKOT5sjJRgxBCOjwpf/suWLAAt912GyZOnIhJkyZh0aJFqKurw7x58wAAt956K/r06YOFCxcCiJku7NixQ//56NGj2LRpEwoKCjB06NAMngohhGQXommClZtc76K4K9zZupDjvkQDBUkCPvu/M3GmLoTjVY24dfE6/eb60nN6NnfYpBWImPoMiT2nCCGEtB4pi6Ebb7wRJ0+exEMPPYTy8nKMHz8eb7/9tm6qcOjQIchCc8Fjx47hvPPO018/8cQTeOKJJ3DppZdi5cqVzT8DQgjJUkRzsO75/oT3RYfBZG6DPqFPkSRJKMrzoyjPj8E9C7D1R7MRiig4eLoe4/sVNXvcpOUxR/V8dJskhJA2Ia24/Pz5823T4swCZ+DAgVDVxFQOQgjp6EiShD/dPhkN4ajBRlvkNzefh/d2ncB15zn3lwl47WtK8vxe5PmB8XmJgotkJ2YDBZ+XYogQQtoCJikTQkgLcsmwYsf3rxrXG1eNszdO0PDzZrlDYa4Z8nvYY4gQQtoCXl0JIaQdwDSqjkXY1GeIv19CCGkb+O1LCCHtAEaGOhYJaXIUQ4QQ0ibw25cQQtoBAd4sdyjMaXI+pskRQkibwKsrIYS0AxgZ6liYm64yMkQIIW0Dv30JIaQdMHlwdwAURR2FqKlmaGzforYZCCGEdHLoJkcIIe2AXl1z8fEPLkeXHH5tdwRuu3AAimq/wKxpF6O0KM/Wep0QQkjLwqsqIYS0E/oU5bb1EEiGGNwzH8O7qji3TyF8Pl9bD4cQQjotzLcghBBCCCGEdEoohgghhBBCCCGdEoohQgghhBBCSKeEYogQQgghhBDSKaEYIoQQQgghhHRKKIYIIYQQQgghnRKKIUIIIYQQQkinhGKIEEIIIYQQ0imhGCKEEEIIIYR0SiiGCCGEEEIIIZ0SiiFCCCGEEEJIp4RiiBBCCCGEENIpoRgihBBCCCGEdEoohgghhBBCCCGdEm9bD8ANqqoCAKqrq9PaPhwOo76+HtXV1fD5fJkcWqeC85gZOI/Nh3OYGdzMo/a9q30Pkxi8LmUHnMfMwHnMDJzHzNDa16Z2IYZqamoAAP369WvjkRBCSOekpqYGXbt2bethZA28LhFCSNuTiWuTpLaDx32KouDYsWPo0qULJElKefvq6mr069cPhw8fRmFhYQuMsHPAecwMnMfmwznMDG7mUVVV1NTUoHfv3pBlZlZr8LqUHXAeMwPnMTNwHjNDa1+b2kVkSJZl9O3bt9n7KSws5IczA3AeMwPnsflwDjNDsnlkRCgRXpeyC85jZuA8ZgbOY2ZorWsTH/MRQgghhBBCOiUUQ4QQQgghhJBOSacQQ4FAAA8//DACgUBbD6Vdw3nMDJzH5sM5zAycx7aDc58ZOI+ZgfOYGTiPmaG157FdGCgQQgghhBBCSKbpFJEhQgghhBBCCDFDMUQIIYQQQgjplFAMEUIIIYQQQjolFEOEEEIIIYSQTkmHF0NPPfUUBg4ciJycHEyePBnr1q1r6yG1KatWrcJVV12F3r17Q5IkvP7664b3VVXFQw89hF69eiE3NxczZ87E3r17DeucOXMGt9xyCwoLC1FUVITbb78dtbW1hnW2bNmCqVOnIicnB/369cPjjz/e0qfWaixcuBAXXHABunTpgpKSElx77bXYvXu3YZ3Gxkbcfffd6NGjBwoKCvCVr3wFFRUVhnUOHTqEL33pS8jLy0NJSQnuvfdeRCIRwzorV67E+eefj0AggKFDh+KFF15o6dNrNZ555hmMHTtWb6o2ZcoU/Otf/9Lf5xymx2OPPQZJkvC9731PX8a5zD54bYrD61Jm4LUpM/DalHmy/rqkdmCWLFmi+v1+dfHixer27dvVO+64Qy0qKlIrKiraemhtxtKlS9UHH3xQffXVV1UA6kj/9fsAAAvoSURBVGuvvWZ4/7HHHlO7du2qvv766+rmzZvVq6++Wh00aJDa0NCgr3PFFVeo48aNUz/55BP1ww8/VIcOHarefPPN+vtVVVVqaWmpesstt6jbtm1TX3rpJTU3N1f97W9/21qn2aLMmTNHff7559Vt27apmzZtUufOnav2799fra2t1df59re/rfbr109dsWKF+tlnn6kXXnihetFFF+nvRyIR9dxzz1Vnzpypbty4UV26dKlaXFysPvDAA/o6n3/+uZqXl6cuWLBA3bFjh/qb3/xG9Xg86ttvv92q59tS/OMf/1Dfeustdc+ePeru3bvVH/7wh6rP51O3bdumqirnMB3WrVunDhw4UB07dqx6zz336Ms5l9kFr01GeF3KDLw2ZQZemzJLe7gudWgxNGnSJPXuu+/WX0ejUbV3797qwoUL23BU2YP5oqMoilpWVqb+4he/0JdVVlaqgUBAfemll1RVVdUdO3aoANRPP/1UX+df//qXKkmSevToUVVVVfXpp59Wu3XrpgaDQX2d+++/Xx0+fHgLn1HbcOLECRWA+sEHH6iqGpszn8+n/u1vf9PX2blzpwpAXbNmjaqqsYu/LMtqeXm5vs4zzzyjFhYW6vN23333qaNHjzYc68Ybb1TnzJnT0qfUZnTr1k39/e9/zzlMg5qaGnXYsGHq8uXL1UsvvVS/6HAusw9em+zhdSlz8NqUOXhtSo/2cl3qsGlyoVAI69evx8yZM/Vlsixj5syZWLNmTRuOLHs5cOAAysvLDXPWtWtXTJ48WZ+zNWvWoKioCBMnTtTXmTlzJmRZxtq1a/V1pk2bBr/fr68zZ84c7N69G2fPnm2ls2k9qqqqAADdu3cHAKxfvx7hcNgwjyNGjED//v0N8zhmzBiUlpbq68yZMwfV1dXYvn27vo64D22djvj5jUajWLJkCerq6jBlyhTOYRrcfffd+NKXvpRwvpzL7ILXptTgdSl9eG1qPrw2NY/2cl3yprR2O+LUqVOIRqOGSQSA0tJS7Nq1q41Gld2Ul5cDgOWcae+Vl5ejpKTE8L7X60X37t0N6wwaNChhH9p73bp1a5HxtwWKouB73/seLr74Ypx77rkAYufo9/tRVFRkWNc8j1bzrL3ntE51dTUaGhqQm5vbEqfUqmzduhVTpkxBY2MjCgoK8Nprr2HUqFHYtGkT5zAFlixZgg0bNuDTTz9NeI+fx+yC16bU4HUpPXhtah68NjWf9nRd6rBiiJDW4O6778a2bdvw0UcftfVQ2iXDhw/Hpk2bUFVVhVdeeQW33XYbPvjgg7YeVrvi8OHDuOeee7B8+XLk5OS09XAIIVkAr03Ng9em5tHerksdNk2uuLgYHo8nwZmioqICZWVlbTSq7EabF6c5Kysrw4kTJwzvRyIRnDlzxrCO1T7EY3QE5s+fjzfffBPvv/8++vbtqy8vKytDKBRCZWWlYX3zPCabI7t1CgsLO8RTIwDw+/0YOnQoJkyYgIULF2LcuHH41a9+xTlMgfXr1+PEiRM4//zz4fV64fV68cEHH+DXv/41vF4vSktLOZdZBK9NqcHrUurw2tR8eG1qHu3tutRhxZDf78eECROwYsUKfZmiKFixYgWmTJnShiPLXgYNGoSysjLDnFVXV2Pt2rX6nE2ZMgWVlZVYv369vs57770HRVEwefJkfZ1Vq1YhHA7r6yxfvhzDhw/vEKkIqqpi/vz5eO211/Dee+8lpF5MmDABPp/PMI+7d+/GoUOHDPO4detWwwV8+fLlKCwsxKhRo/R1xH1o63Tkz6+iKAgGg5zDFJgxYwa2bt2KTZs26f8mTpyIW265Rf+Zc5k98NqUGrwuuYfXppaD16bUaHfXpdS9IdoPS5YsUQOBgPrCCy+oO3bsUO+88061qKjI4EzR2aipqVE3btyobty4UQWgPvnkk+rGjRvVL774QlXVmIVpUVGR+sYbb6hbtmxRr7nmGksL0/POO09du3at+tFHH6nDhg0zWJhWVlaqpaWl6te//nV127Zt6pIlS9S8vLwOY2H6ne98R+3atau6cuVK9fjx4/q/+vp6fZ1vf/vbav/+/dX33ntP/eyzz9QpU6aoU6ZM0d/XLCNnz56tbtq0SX377bfVnj17WlpG3nvvverOnTvVp556qkNZb/7gBz9QP/jgA/XAgQPqli1b1B/84AeqJEnqsmXLVFXlHDYH0bVHVTmX2QavTUZ4XcoMvDZlBl6bWoZsvi51aDGkqqr6m9/8Ru3fv7/q9/vVSZMmqZ988klbD6lNef/991UACf9uu+02VVVjNqb//d//rZaWlqqBQECdMWOGunv3bsM+Tp8+rd58881qQUGBWlhYqM6bN0+tqakxrLN582b1kksuUQOBgNqnTx/1sccea61TbHGs5g+A+vzzz+vrNDQ0qHfddZfarVs3NS8vT73uuuvU48ePG/Zz8OBB9corr1Rzc3PV4uJi9fvf/74aDocN67z//vvq+PHjVb/frw4ePNhwjPbON7/5TXXAgAGq3+9Xe/bsqc6YMUO/2Kgq57A5mC86nMvsg9emOLwuZQZemzIDr00tQzZflyRVVdXUYkmEEEIIIYQQ0v7psDVDhBBCCCGEEOIExRAhhBBCCCGkU0IxRAghhBBCCOmUUAwRQgghhBBCOiUUQ4QQQgghhJBOCcUQIYQQQgghpFNCMUQIIYQQQgjplFAMEUIIIYQQQjolFEOEZIhvfOMbuPbaa9t6GIQQQggAXpcIcQPFECGEEEIIIaRTQjFESIq88sorGDNmDHJzc9GjRw/MnDkT9957L/7whz/gjTfegCRJkCQJK1euBAAcPnwYN9xwA4qKitC9e3dcc801OHjwoL4/7cndI488gp49e6KwsBDf/va3EQqF2uYECSGEtCt4XSIkfbxtPQBC2hPHjx/HzTffjMcffxzXXXcdampq8OGHH+LWW2/FoUOHUF1djeeffx4A0L17d4TDYcyZMwdTpkzBhx9+CK/Xi0cffRRXXHEFtmzZAr/fDwBYsWIFcnJysHLlShw8eBDz5s1Djx498NOf/rQtT5cQQkiWw+sSIc2DYoiQFDh+/DgikQiuv/56DBgwAAAwZswYAEBubi6CwSDKysr09f/0pz9BURT8/ve/hyRJAIDnn38eRUVFWLlyJWbPng0A8Pv9WLx4MfLy8jB69Gj8+Mc/xr333ouf/OQnkGUGcAkhhFjD6xIhzYOfZkJSYNy4cZgxYwbGjBmDf/u3f8Nzzz2Hs2fP2q6/efNm7Nu3D126dEFBQQEKCgrQvXt3NDY2Yv/+/Yb95uXl6a+nTJmC2tpaHD58uEXPhxBCSPuG1yVCmgcjQ4SkgMfjwfLly7F69WosW7YMv/nNb/Dggw9i7dq1luvX1tZiwoQJ+POf/5zwXs+ePVt6uIQQQjo4vC4R0jwohghJEUmScPHFF+Piiy/GQw89hAEDBuC1116D3+9HNBo1rHv++efj5ZdfRklJCQoLC233uXnzZjQ0NCA3NxcA8Mknn6CgoAD9+vVr0XMhhBDS/uF1iZD0YZocISmwdu1a/OxnP8Nnn32GQ4cO4dVXX8XJkycxcuRIDBw4EFu2bMHu3btx6tQphMNh3HLLLSguLsY111yDDz/8EAcOHMDKlSvx3e9+F0eOHNH3GwqFcPvtt2PHjh1YunQpHn74YcyfP5952YQQQhzhdYmQ5sHIECEpUFhYiFWrVmHRokWorq7GgAED8D//8z+48sorMXHiRKxcuRITJ05EbW0t3n//fUyfPh2rVq3C/fffj+uvvx41NTXo06cPZsyYYXgiN2PGDAwbNgzTpk1DMBjEzTffjB/96Edtd6KEEELaBbwuEdI8JFVV1bYeBCGdmW984xuorKzE66+/3tZDIYQQQnhdIp0KxjoJIYQQQgghnRKKIUIIIYQQQkinhGlyhBBCCCGEkE4JI0OEEEIIIYSQTgnFECGEEEIIIaRTQjFECCGEEEII6ZRQDBFCCCGEEEI6JRRDhBBCCCGEkE4JxRAhhBBCCCGkU0IxRAghhBBCCOmUUAwRQgghhBBCOiUUQ4QQQgghhJBOyf8HUeIvUF5giA0AAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 1000x500 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#画线要注意的是损失是不一定在零到1之间的\n",
    "def plot_learning_curves(record_dict, sample_step=500):\n",
    "    # build DataFrame\n",
    "    train_df = pd.DataFrame(record_dict[\"train\"]).set_index(\"step\").iloc[::sample_step]\n",
    "    val_df = pd.DataFrame(record_dict[\"val\"]).set_index(\"step\")\n",
    "\n",
    "    # plot\n",
    "    fig_num = len(train_df.columns)\n",
    "    fig, axs = plt.subplots(1, fig_num, figsize=(5 * fig_num, 5))\n",
    "    for idx, item in enumerate(train_df.columns):    \n",
    "        axs[idx].plot(train_df.index, train_df[item], label=f\"train_{item}\")\n",
    "        axs[idx].plot(val_df.index, val_df[item], label=f\"val_{item}\")\n",
    "        axs[idx].grid()\n",
    "        axs[idx].legend()\n",
    "        # axs[idx].set_xticks(range(0, train_df.index[-1], 5000))\n",
    "        # axs[idx].set_xticklabels(map(lambda x: f\"{int(x/1000)}k\", range(0, train_df.index[-1], 5000)))\n",
    "        axs[idx].set_xlabel(\"step\")\n",
    "    \n",
    "    plt.show()\n",
    "\n",
    "plot_learning_curves(record, sample_step=10)  #横坐标是 steps"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 评估"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2025-01-24T11:08:01.453199Z",
     "iopub.status.busy": "2025-01-24T11:08:01.452735Z",
     "iopub.status.idle": "2025-01-24T11:08:05.299758Z",
     "shell.execute_reply": "2025-01-24T11:08:05.299143Z",
     "shell.execute_reply.started": "2025-01-24T11:08:01.453166Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loss:     0.3493\n",
      "accuracy: 0.8666\n"
     ]
    }
   ],
   "source": [
    "# dataload for evaluating\n",
    "\n",
    "# load checkpoints\n",
    "model.load_state_dict(torch.load(\"checkpoints/imdb-lstm/best.ckpt\", weights_only=True,map_location=\"cpu\"))\n",
    "\n",
    "model.eval()\n",
    "loss, acc = evaluating(model, test_dl, loss_fct)\n",
    "print(f\"loss:     {loss:.4f}\\naccuracy: {acc:.4f}\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
